Algorithm Study

아이템17. 변경 가능성을 최소화하라

hyun-1200 2022. 6. 24. 14:57

아이템17. 변경 가능성을 최소화하라

  • 불변 클래스란 그 인스턴스와 내부 값을 수정할 수 없는 클래스다. 불변 인스턴스에 간직된 정보는 고정되어 객체가 파괴되는 순간까지 절대 달라지지 않는다.

불변클래스를 만들기 위한 다섯가지 규칙

  1. 객체의 상태를 변경하는 메서드(변경자)를 제공하지 않는다.
  2. 클래스를 확장할 수 없도록 한다.
  3. 모든 필드를 final로 선언한다.
  4. 모든 필드를 private으로 선언한다.
  5. 자신 외에는 내부의 가변 컴포넌트에 접근할 수 없도록 한다.
  • 함수형 프로그래밍 : 피연산자에 함수를 적용해 결과를 반환하지만, 피연산자 자체는 그대로인 프로그래밍 패턴
    • 메서드 이름을 동사형(ex.add) 대신 전치사형(ex.plus)로 사용하여 강조한다.
    • 함수형 프로그래밍을 사용하면 불변이 되는 영역의 비율을 높아지는 장점을 누릴 수 있다.
  • 절차적/명령형 프로그래밍 : 메서드에서 피연산자인 자신을 수정해 자신의 상태가 변하게 된다.

불변 객체의 특징

  1. 불변 객체는 단순하다 : 불변객체는 생성시점부터 파괴될때까지 상태를 그대로 간직한다.
  2. 불변 객체는 근본적으로 스레드 안전하여 따로 동기화할 필요가 없다.
  3. 불변 객체는 안심하고 공유할 수 있다.
  4. 불변 객체는 자유롭게 공유할 수 있음은 물론, 불변 객체끼리는 내부 데이터를 공유할 수 있다.
  5. 객체를 만들 때 다른 불변 객체들을 구성요소로 사용하면 이점이 많다.
  6. 불변 객체는 그 자체로 실패원자성을 제공한다 : 실패원자성? 메서드에서 예외가 발생한 후에도 그 객체는 여전히 호출전과 똑같은 유효한 상태.
    • 상태가 절대 변하지 않으니 잠깐이라도 불일치 상태에 빠질 가능성이 없다.

불변 클래스의 단점

  1. 값이 조금이라도 다르면 반드시 독립된 객체로 만들어야 한다. ex. 백만 비트짜리 BigInteger에서 비트 하나를 바꿔야 한다면 새로운 객체로 만들어야 한다.
    • 이러한 문제를 해결하기 위해서는 다단계연산들을 예측하여 기본 기능으로 제공하는 방법이 있다.
    • 가변 동반 클래스

불변 클래스로 만드는 또다른 설계 방법 : 상속하지 못하게 만들자.

  • final클래스로 선언하는 것도 맞지만, 더 유연한 방법이 있다.
  • 모든 생성자를 private 혹은 package-private으로 만들고 public 정적 팩터리를 제공하는 방법이다.
public 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);
  }
}

정리

클래스는 꼭 필요한 경우가 아니라면 불변이여야 한다. 모든 클래스를 불변으로 만들수는 없지만, 불변으로 만들수 없는 클래스라도 변경할 수 있는 부분을 최소한으로 줄이자. 다른 합당한 이유가 없다면 모든 필드는 private final이여야 한다. 생성자는 불변식 설정이 모두 완료된, 초기화가 완벽히 끝난 상태의 객체를 생성해야 한다.