Post

Item 17 - 변경 가능성을 최소화하라

불변 클래스

  • 인스턴스의 내부 값을 수정할 수 없는 클래스
    • ex. String, BigInteger, BigDecimal, 기본 박싱 클래스들
  • 불변 클래스는 가변 클래스보다 설계/구현/사용이 쉽고, 오류가 생길 여지도 적다.

불변 클래스를 만들기 위한 규칙

  • 객체의 상태를 변경하는 메서드를 제공하지 않는다.
  • 클래스를 확장할 수 없음 : 하위 클래스에서 객체의 상태를 변하게 만드는 사태를 막기 위함.
  • 모든 필드를 final로 선언한다. (JLS 17.5) : 여러 스레드에서 접근해도 값이 바뀌지 않음.
  • 모든 필드를 private으로 선언한다. (아이템 15, 16) : 직접 접근해서 수정하지 못하도록 함.
  • 자신 외에는 내부의 가변 컴포넌트에 접근할 수 없도록 한다.
    • 가변 객체를 참조하는 필드가 있다면 클라이언트가 접근하지 못하도록 해야 한다.
    • 접근자 메서드로 반환해서도 안된다.
    • 생성자, 접근자, readObject 메서드 모두에서 방어적 복사를 수행해야 한다.

불변 클래스의 장점

  • 함수형 프로그래밍에 적합하다.
    • 피연산자에 함수를 적용한 결과를 반환하지만 피연산자가 바뀌지는 않는다.
  • 불변 객체는 단순하다.
  • 불변 객체는 근본적으로 스레드 안전하여 따로 동기화할 필요가 없다.
  • 불변 객체는 안심하고 공유할 수 있다. 최대한 한번 만든 인스턴스를 재활용하라.
    • 자주 사용되는 인스턴스를 캐싱하여 중복 생성하지 않게 정적 팩터리를 제공할 수 있다.
  • 불변 객체끼리는 내부 데이터를 공유할 수 있다.
  • 객체를 만들 때 다른 불변 객체들을 구성요소로 사용하면 이점이 많다. (불변식 유지 수월)
  • 불변 객체는 그 자체로 실패 원자성을 제공한다. (아이템 76)

불변 클래스의 단점

  • 값이 다르다면 반드시 별도의 객체로 만들어야 한다.
    • 원하는 객체를 만들기까지 여러 단계가 걸린다면, 그 중간 단계에서 만들어진 객체들이 버려지므로 성능 문제가 있다.
    • “다단계 연산”을 제공하거나, “가변 동반 클래스”를 제공하여 대처할 수 있다.
    • ex. String 클래스의 가변 동반 클래스는 StringBuilder

불변 클래스를 만드는 설계 방법

  • 클래스가 불변임을 보장하기 위해 상속을 못하게 하는 방법에는 final 클래스가 있다.
  • 상속을 막을 수 있는 다른 방안(더 유연함) : private 또는 package-private 생성자 + 정적 팩터리
    • 확장이 가능하고, 다수의 package-private 구현 클래스를 만들 수 있다.
    • 정적 팩터리를 사용해 여러 구현 클래스중 하나를 활용할 수 있는 유연성을 제공하고, 객체 캐싱 기능으로 성능을 향상 시킬 수도 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
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이어야 한다.
  • 생성자는 불변식 설정이 모두 완료된(초기화가 끝난) 상태의 객체를 생성해야 한다.

참고 🕶️

This post is licensed under CC BY 4.0 by the author.