티스토리 뷰
반응형
불변 클래스
- 그 인스턴스의 내부 값을 수정할 수 없는 클래스
ex)String, 기본 타입 박싱 클래스들, BigInteger, BigDecimal - 가변 클래스보다 설계/구현/사용이 쉬움, 오류가 더 적음
불변 클래스를 만들기 위한 규칙
- 객체의 상태를 변경하는 메서드를 제공하지 않음
- 클래스를 확장할 수 없음 (하위 클래스에서 객체의 상태를 변하게 만드는 사태를 막기 위함)
- 모든 필드를 final로 선언 : 여러 스레드에서 접근해도 값이 바뀌지 않음
- 모든 필드를 private 으로 선언 : 직접 접근해서 수정하지 못하도록 함
- 자신 외에는 내부의 가변 컴포넌트에 접근할 수 없도록 함
- 가변 객체를 참조하는 필드가 있다면 클라이언트가 접근하지 못하도록 해야함
- 접근자 메서드로 반환해서도 안됨.
- 생성자, 접근자, readObject 메서드 모두에서 방어적 복사를 수행해야함
불변 객체
//불변 클래스
public final class Complex {
private final double re;
private final double im;
public Complex(double re, double im) {
this.re = re;
this.im = re;
}
//생략..
public Complex plus(Complex c) {
return new Complex(re + c.re, im + c.im);
}
public Complex minus(Complex c) {
return new Complex(re - c.re, im - c.im);
}
//생략..
}
plus()와 minus()를 보면 인스턴스 자신은 수정하지 않고 새로운 Complex 인스턴스를 만들어 반환한다.
즉, 피연산자 자체는 그대로이다. (함수형 프로그래밍)
→ 불변 객체는 말 그대로 생성된 시점부터 파괴될 때까지 그대로인 것을 말한다.
불변 객체의 장점
- 불변 객체는 근본적으로 스레드 안전하여 따로 동기화할 필요가 없다.
- 불변 객체는 안심하고 공유할 수 있다. 최대한 한번 만든 인스턴스를 재활용해라.
자주 사용되는 인스턴스를 캐싱하여 중복 생성하지 않게 정적 팩터리를 제공할 수 있다. - 불변 객체끼리는 내부 데이터를 공유할 수 있다.
- 객체를 만들 때 다른 불변 객체들을 구성요소로 사용하면 이점이 많다. (불변식 유지 수월)
- 불변 객체는 그 자체로 실패 원자성을 제공한다.
실패 원자성 : 메서드에서 예외 발생 후에도 그 객체는 유효한 상태여야한다.
불변 객체의 단점
불변 클래스는 값이 다르면 반드시 독립적인 객체로 만들어야한다.
원하는 객체를 만들기까지 여러 단계가 걸린다면, 그 중간단계에서 만들어진 객체들이 버려지므로 성능 문제가 있다.
→ 이런 다단계 연산을 기본으로 제공하여 속도를 높여주는 가변 동반 클래스로 해결한다.
ex) String 클래스의 가변 동반 클래스는 StringBuilder
불변 클래스를 만드는 설계 방법
클래스가 불변임을 보장하기 위해 상속을 못하게 하는 방법에는 대표적으로 final 클래스가 있다.
그러나 더 유연한 방법으로, 모든 생성자를 private 이나 package-private 으로 만들고 public 정적 팩터리를 제공하는 방법이 있다.
public final class Complex {
private final double re;
private final double im;
private Complex(double re, double im) {
this.re = re;
this.im = re;
}
public static Complex valueOf(double re, double im) {
return new Complex(re, im);
}
}
결론
클래스는 꼭 필요한 경우가 아니라면 불변이어야 한다. (getter가 있다고 해서 꼭 setter를 만들지는 말자)
불변으로 만들수 없으면 변경할 수 있는 부분을 최소한으로 줄이자.
꼭 변경해야할 필드를 빼고는 final로 선언하자.
합당한 이유가 없다면 모든 필드는 private final 이어야한다.
생성자는 불변식 설정이 모두 완료된(초기화가 끝난) 상태의 객체를 생성해야한다.
반응형
'Java > Effective Java' 카테고리의 다른 글
[Effective Java] 19.상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라 (0) | 2022.03.16 |
---|---|
[Effective Java] 18.상속보다는 컴포지션을 사용하라 (0) | 2022.03.12 |
[Effective Java] 16.public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라 (0) | 2022.03.12 |
[Effective Java] 15.클래스와 멤버의 접근 권한을 최소화하라 (0) | 2022.03.12 |
[Effective Java] 14.Comparable을 구현할지 고려하라 (0) | 2022.03.12 |
댓글