[Effective Java] Item17. 불변클래스를 이용하여 변경가능성을 최소화 하라

2024. 3. 16. 21:43Java/Effective Java

반응형

불변 클래스는 단순합니다.

그렇기 때문에 가변클래스보다 설계/구현/사용이 쉽습니다.

불변 객체는 생성시점부터 사용을 마치는 시점까지 값을 그대로 유지하기 때문에, 예상치 못한 오류를 방지할 수 있어서 안전합니다.
ThreadSafe하고, 여러 스레드가 동시에 사용하더라도 훼손되지 않으며, 재활용이 편리합니다.


클래스를 불변으로 만들기 위해서는 아래의 규칙을 따라야 합니다.

  • setter 를 제공하지 않는다
    • 객체 내의 필드값을 수정할 수 없도록 합니다.
  • 클래스를 final 설정하여 클래스를 확장할 수 없도록 합니다
    • 하위 클래스를 통한 확장 중, 의도치 않게 객체 내의 필드값을 수정하는 상황이 발생할 수 있습니다.
  • 모든 필드를 final로 선언합니다.
    • ThreadSafe 하기 때문에 새로 생성된 인스턴스를 동기화 없이 다른 스레드로 건넬수 있게 합니다.
  • 모든 필드를 private 선언합니다.
    • 객체 내의 필드를 클라이언트 측에서 직접 수정할 수 없게 해줍니다.
  • 클래스 내의 가변 요소는 본인(해당 클래스)만 접근할 수 있도록 합니다

Java 14 에서는 불변 클래스를 record 키워드로 생성할 수 있으니, record 클래스로 불변 클래스를 생성하면 됩니다.

불변객체는 자유롭게 공유가 가능하기 때문에, clone 하지 않고, 그자체를 여러곳에서 활용할 수 있습니다.

때문에, 불변객체를 복제하는 것은 무의미하고(그 자체를 활용하면 되기 때문에)
클래스를 복사하는 clone같은 메서드는 제공하지 않는것을 권장합니다.

다만, 내부 값이 조금이라도 다를 경우, 객체를 하나더 만들어야합니다.
때문에, 만약 만들어야하는 불변객체가 많다면 그에 따른 비용이 발생된다는 단점이 있습니다.


불변 객체를 만드는 또다른 방법

위에서 제시하는 방법을 제외하고, 설계적인 방법으로 불변 객체를 만드는 방법이 있습니다.

바로, 모든 생성자를 private 또는 package-private으로 설정하고, 정적 팩터리 메서드를 이용하여 객체를 생성하는 방법입니다.
public/protected 생성자가 없기 떄문에 클래스 확장도 불가능하기 떄문에 논리적으로 final 합니다.

@Getter
public class Complex {
    private double re;
    private double im;

    private Complex(double re, double im) {
        this.re = re;
        this.im = im;
    }

    public static Complex valueOf(double re, double im) {
        return new Complex(re, im);
    }
}

단순하면서, 예상치 못한 오류를 방지할 수 있도록 불변 클래스/객체를 사용하는 것을 권장하지만
만일 불변 클래스로 정의할 수 없다면 최대한 변경할 수 있는 요소를 최소한으로 하는 것을 권장합니다.

객체를 재활용할 목적으로 내부 필드값을 다시 초기화해서는 안되며, 정적 팩터리 메서드를 통해 객체를 생성한 후, 값이 변경되지 않도록 클래스를 정의하는 것을 권장합니다.


++

  • Item 17. 변경가능성을 최소화 하라.
728x90
반응형