불변 클래스란 간단히 말해 그 인스턴스의 내부 값을 수정할 수 없는 클래스다.
특징
불변 인스턴스에 간직된 정보는 고정되어 객체가 파괴되는 순간까지 달라지지 않는다.
자바 플랫폼 라이브러리에도 String, BigInteger, BigDecimal가 여기 속한다.
그렇다면 왜 불변 클래스를 사용할까?
불변 클래스는 가변 클래스보다 설계하고 구현하고 사용하기 쉬우며, 오류의 여지도 적고 안전하다.
이제 클래스를 불변으로 만드는 다섯가지 규칙에 대해 알아보자.
이러한 불변 클래스의 규칙을 통해 만들어진 예제를 보자
public final class Complex {
private final double re;
private final double im;
public Complex(double re, double im) {
this.re = re;
this.im = im;
}
public double realPart() {
return re;
}
public double imaginaryPart() {
return im;
}
public Complex plus(Complex complex) {
return new Complex(re + complex.re, im + complex.im);
}
// ...
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Complex complex = (Complex) o;
return Double.compare(complex.re, re) == 0 && Double.compare(complex.im, im) == 0;
}
@Override
public int hashCode() {
return Objects.hash(re, im);
}
}
그렇다면 이런 불변 클래스를 사용함으로 써 가져오는 이점은 무엇일까?
//예제
public static final Complex ZERO = new Complex(0,0);
public static final Complex One = new Complex(1,0);
public static final Complex I = new Complex(0,1);
앞서 불변 클래스의 장점을 보았을 때는 그럼 이러한 객체를 사용하지 않을 이유가 없자나! 라고 생각할 수 있다. 하지만 이러한 불변 클래스에도 단점이 존재 한다.
앞서 불변 클래서의 장단점을 알아 보았고, 불변 클래스를 만드는 방법을 알아볼텐데 그중 생성자를 대신 정적 팩터리를 사용한 불변 클래스 방법에 대해 알아보자
그전에 불변 클래스 생성 필요한 규칙인 클래스가 불변임을 보장하려면 자신을 상속하지 못하게 해야 하는점을 생각해보자.
public final class Complex {
private final double re;
private final 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);
}
// ...
}
이런 내용들을 정리해 보자면,
클래스는 꼭 필요한 경우가 아니라면 불변이어야 한다.
단순한 값 객체는 불변으로 만들도록 하자.
성능 때문에 어쩔 수 없다면 불변 클래스와 함께 가변 동반 클래스를 public 클래스로 제공하도록 하자.
모든 클래스를 불변으로 만들 수는 없다. 하지만 불변으로 만들 수 없는 클래스라도 변경할 수 있는 부분을 최소한으로 줄이도록 하자.
생성자는 불변식 설정이 모두 완료된, 초기화가 완벽히 끝난 상태의 객체를 생성해야 한다.