반응형

ITEM 17 "변경 가능성을 최소화하라"

 

제목을 보자마자 들었던 생각은 OCP(Open Close Priciple) 원칙이다.

"확장에 대해서는 열려 있어야 하고 수정에 대해서는 닫혀 있어야 한다"라는 뜻인데 이 원칙을 잘 지켜야 구조가 좋아지고 코드 품질이 훌륭해진다. 협업을 위해 반드시 지켜야 되는 개념이기도 하다.

 

이번 장에서는 불변 클래스로 만드는 것을 권장하고 있다.

 

불변 클래스

= 객체가 파괴되는 순간까지 인스턴스의 내부 값을 수정할 수 없는 클래스

 

불변 클래스 특징

이러한 불변 클래스가 되려면 아래와 같은 특징을 가져야 한다.

 

1 . 객체의 상태를 변경하는 메서드를 제공하지 않는다.

2 . 클래스를 확장할 수 없도록 한다. 하위 클래스가 상속하여 객체의 상태를 바꿀 수 있으므로 상속을 막기 위함이다.

3 . 모든 필드를 final 로 선언한다.

4 . 모든 필드를 private 로 선언한다. 필드가 참조하는 가변 객체를 다른 쪽에서 수정한다면 side effect 가 발생한다.

5 . 자신 외에는 내부의 가변 컴보넌트에 접근할 수 없도록 한다.

TIP . 메서드들이 인스턴스 자신을 수정하지 않고 새로운 인스턴스를 반환하게 작성하면 안전하게 사용될 수 있다.

(이런 패턴을 함수형 프로그래밍이라고 한다. 메서드가 호출되어도 객체의 상태를 변경하지 않는 것을 의미한다.)

 

불변 객체는 가변 객체와 다르게 근본적으로 Thread-Safe 하며 따로 동기화할 필요가 없다.

또한 만약 가변 객체였다면 임의의 복잡한 상태에 놓일 수 있다. 끔찍하게 도미노처럼 side effect 가 연쇄적으로 발생할 수도 있다. 그래서 상태를 변경하는 메서드들의 상태 전이들을 정밀하게 문서화하지 않는다면 믿고 쓰기가 어렵다.

불변 객체는 실패 원자성을 제공한다. 불변 객체를 사용하는 임의의 메서드에서 예외가 발생한 후에도 불변 객체는 내부 상태를 바꾸지 않으니 실패하더라도 원자성을 제공한다.

 

안심하고 공유할 수 있기에 생성된 인스턴스를 최대한 재활용하는 것을 권장하고 있다. 아이템 1에서 소개한 정적 팩토리 메서드를 제공하는 것도 하나의 방법이다.

 

불변 클래스 단점

장점이 많아 보이는 불변 객체도 단점은 존재한다. 값이 다르다면 반드시 독립된 객체로 만들어야 한다.

불변 객체는 상수와 유사하기 때문에 값이 조금이라도 틀려진다면 새롭게 객체를 하나 생성해야 한다.

 

심지어 객체를 완성하는데 무거운 작업들이 수행되거나 중간 단계에서 만들어진 객체들이 모두 버려진다면 성능 이슈도 생기게 된다. 이 문제점을 해결하기 위해 2 가지가 있다.

 

1 . 다단계 연산을 제공하여 에측하여 기본 기능으로 제공한다.

2 . 다단계 연산이 예측이 되지 않는다면 가변 동반 클래스를 public 으로 제공한다.

 

불변 클래스를 만드는 방법

자신의 클래스를 상속하지 못하게 final 클래스로 선언하거나,

모든 생성자를 private 혹은 package-private 로 만들고 public 정적 팩토리를 제공하자.

 

성능을 위해서 불변 클래스 규칙을 완화

정책을 "어떤 메서드도 객체의 상태 중 외부에 비치는 값을 변경할 수 없다"로 변경한다.

외부 상태 값이 아니라 내부 상태 값만 변경해야 한다.

반응형

+ Recent posts