티스토리 뷰
https://edu.nextstep.camp/c/8fWRxNWU/
일급컬렉션 피드백에 이어, 많이 하는 피드백이 불변객체를 작성하라는 것이다.
Effective Java에서는 '변경 가능성을 최소화하라'는 챕터를 통해 불변 객체를 소개한다. '불변 객체'는 인스턴스 생성 이후 내부 인스턴스 변수들을 수정할 수 없어야 한다. 이에 근본적으로 Thread-safe하므로 동기화 작업을 할 필요 없어 오류 가능성이 적고 실패 원자성을 제공한다.
불변 객체를 작성하기 위해 Effective Java에서는 아래의 규칙을 소개한다.
- 객체의 상태를 변경하는 메서드를 제공하지 않는다. 즉, setter 메서드 등을 통해 인스턴스 변수의 값을 변경하는 메서드를 작성하지 않아야 한다.
- 클래스를 확장할 수 없도록 한다. 그리하여 하위 클래스에서 의도치 않게 인스턴스 변수를 변경하는 것을 막아야 한다. 정적 팩토리 메서드를 작성한다면 생성자를 private으로 작성하기에 다른 패키지에서 이 클래스를 확장하는 것이 불가능해진다. 그 외에도 final class로 선언하고 모든 멤버 필드를 final로 적옹하여 상속을 막을 수 있다.
- 모든 필드를 final로 선언한다. java에서 final 예약어는 해당 객체를 가리키는 포인터를 바꿀 수 없게하는 의미를 까지지만, 코드 작성자의 의도를 명확히 드러내는 것만으로도 유의미하다.
- 모든 필드를 private으로 선언하여 직접 멤버 필드에 접근하는 것을 막을 수 있다.
- 자신 외에는 내부의 가변 컴포넌트에 접근할 수 없도록 한다. 즉, 외부에 인스턴스 변수를 반환할 경우 (getter 등에서) 방어적 복사본을 만들어야 한다. - 관련 링크
이 포스팅은, Collections 라이브러리의 unmodifiableList API를 어떻게 활용하는 것이 좋을지 피드백하다 작성하게 되었다. unmodifiableList 는 List에 read-only 상태로 접근 가능하도록 하며, List에 수정을 가하려고 할 경우 UnsupportedOperationException를 반환하도록 한다. - 관련 링크
final class ImmutableCart<T> {
private final List<T> items;
public ImmutableCart(final List<T> items) {
this.items = Collections.unmodifiableList(items);
}
public List<T> getItems() {
return new ArrayList(items);
}
}
unmodifiableList를 생성자에서 사용하여 전달받은 값을 방어적 복사하고, getter에서 객체를 생성해서 반환하는 것도 좋은 전략이라고 생각한다. final 예약어를 사용하였으므로 값을 재할당할 수 없으며, unmodifiableList는 값을 수정할 시에 예외를 발생시키므로 Item을 교체하지 못한다는 의미가 분명해질 수 있다. 이에 내부에서 값을 재정의하는 메서드를 작성하는 것을 방지하는 효과를 가져온다.
getter에서도 unmodifiableList를 사용할 경우 Deep Copy가 되지 않는다는 점이 우려가 있지만, Item이 Value Object로 작성하여 불변성을 보장할 경우 속성을 변경할 수 없고 Collection에 직접 Item을 교체하는 api를 제공하지 않으므로 불변을 보장할 수는 있다. 다만, 이 경우 외부 사용자 측면에서는 기대하지 않은 예외 (unsupportedoperationexception)에 직면하여 좋지 못한 경험을 준다는 단점이 있으며, unmodifiableList은 비즈니스 로직을 읽어내는데 저해된다는 주장도 있다.
추가적으로, 위키에서는 불변객체 작성시에 생성자에서는 방어적 복사 후 Collection 요소들의 타입 검사까지 진행하며, getter에서는 내부 필드의 방어적 복사를 수행하도록 가이드 한다.
결국, 불변객체를 어떻게 작성할 지는 답이 있는 영역이라기보다는, 팀 컨벤션으로 조율해갈 문제라고 생각한다. Effective Java에서 가이드하는 불변성을 보장하는 범위에서 어떻게 구현할지 합당한 논리만 견지하시면 좋다고 생각한다.
'Programming > .java' 카테고리의 다른 글
일급컬렉션에 대하여 (0) | 2020.03.30 |
---|---|
스프링 프레임워크에 이르기까지 <2> MVC (0) | 2017.10.02 |
스프링 프레임워크에 이르기까지 <1> All-in-one (0) | 2017.09.23 |
[Java]Collections Class (0) | 2017.08.26 |
[Java]String vs StringBuffer vs StringBuilder (0) | 2017.08.25 |