Skip to content

Latest commit

 

History

History
71 lines (49 loc) · 4.46 KB

File metadata and controls

71 lines (49 loc) · 4.46 KB

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

  • 변경 가능성을 최소화하라는 것은 불변성(불변 클래스)의 중요성과 연결된다.
  • 불변 클래스란 그 인스턴스의 내부 값을 수정할 수 없는 클래스이다.
  • 불변 인스턴스 정보는 고정되어 객체가 파괴되는 순간까지 절대 달라지지 않는다.
  • 자바 플랫폼 라이브러리 불변클래스 : String, 기본 타입의 박싱된 클래스들, BigInteger, BigDecimal

불변 클래스의 특징

  • 불변 클래스는 가변 클래스보다 설계, 구현, 사용이 쉬우며 오류 가능성이나 여지도 적고 훨씬 안전하다.
  1. 객체의 상태를 변경하는 메서드(변경자)를 제공하지 않는다.
  2. 클래스를 확장할 수 없도록 한다.
  3. 모든 필드를 final로 선언한다.
  4. 모든 필드를 private로 선언한다.
  5. 자신 외에는 내부 가변 컴포넌트에 접근할 수 없도록 한다.
    • 변경이 필요하다면, 방어적 복사를 통해 수행할 수 있다.

불변 클래스의 장점

불변 객체는 근본적으로 thread safe하므로 따로 동기화할 필요가 없다. 불변 객체는 다른 스레드에 영향을 줄 수 없으므로, 안심하고 공유할 수 있다. 따라서, 불변 클래스는 이미 만든 인스턴스를 최대한 재활용하는 것이 좋다.

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);
  • 이와 같이 자주 쓰이는 값을 상수로 제공하여 쉽게 재활용 할 수 있게 만들었다.

  • 불변 클래스는 자주 사용되는 인스턴스를 캐싱하여 같은 인스턴스를 중복 생성하지 않도록 정적 팩터리를 제공할 수 있으며, 박싱된 기본 타입 클래스 전부와 BigInteger 등이 있다.

  • 정적 팩터리를 사용하면 여러 클라이언트가 인스턴스를 공유해 메모리 사용량과 가비지 컬렉션 비용이 줄어든다.

  • 불변 객체는 자유롭게 공유할 수 있고, 불변 객체끼리는 내부 데이터를 공유할 수 있다.

  • 객체 생성시 다른 불변 객체들을 구성요소로 사용하면 이점이 많다.

    • ex. MapKeySet 원소로 사용하기 좋다.
  • 불변 객체는 그 자체로 실패 원자성을 제공한다. (추후 Item76)

    • 실패 원자성 : 메서드에서 예외 발생 후에도 해당 객체는 메서드 호출 전과 동일한 유효한 상태인 것

불변 클래스의 단점

  • 값의 변경이 필요할 때, 반드시 독립적인 객체로 새로 만들어서 사용해야 한다.
    • 생성, 관리해야하는 객체가 많아질 경우 비용 소모가 크다.
  • 상속이 불가능하다. (final 클래스가 되므로) 재사용이 필요한경우 컴포지션으로 확장해야한다. (Item18)
  • 방어적 복사를 수행할 때, 데이터 내부 구조가 커지면 복사 비용이 증가한다. (퍼포먼스 저하)

Summary

  • Getter 가 있다고 해서 무조건 Setter 를 구현하지 말자 (내부 가변 포인트 제공의 문제)
  • 클래스는 꼭 필요한 경우가 아니라면 불변이여야한다.
  • 불변으로 만들 수 없는 클래스를 만들 때, 가변 포인트를 최대한 줄여야한다. (값 변경이 가능한 지점 최소화)
  • 다른 적절한 이유가 없다면, 모든 필드는 private final 이여야한다.
  • 생성자는 불변식 설정이 모두 완료된 객체를 생성해야한다.
  • 특별한 이유가 없다면, 생성자와 정적 팩토리 메서드 외에는 그 어떤 초기화 메서드도 public 으로 제공하면 안된다. (접근 제한자와 초기화 시 가변 포인트 문제)
  • java.util.concurrent.CountDownLatch는 다음 원칙을 잘 지키고 있다.

CountDownLatch

  • 스레드 간 동기화 도구 (Java Concurrent 패키지 내 존재)
  • 지정된 횟수 만큼(동기화를 위해 메모리 가시성이 있는 volatile int state 사용) 카운트를 세면서 대기중인 스레드를 진행되도록 만드는 동기화 도구이다.

✅ 이 클래스는 다음 원칙을 잘 지킨다

  • 내부 상태 (count)는 외부에서 직접 변경할 수 없음
  • countDown()은 내부적으로만 상태 변경이 허용됨
  • 불필요한 set 메서드 등은 존재하지 않음 → 불필요한 가변 포인트를 노출하지 않음
  • 한 번 count가 0이 되면 그 이후 상태는 변경되지 않음 → 불변 상태 전이