본문은 Effective Java를 읽고 정리한 내용을 기반으로 작성된 글입니다.
클래스를 안전하게 상속할 수 있도록 하려면 (상속만 아니었다면 기술하지 않았어야 할) 내부 구현 방식을 설명해야만 한다.
[상속을 고려한 설계와 문서화]
: 메서드를 정의하면 어떤 일이 일어나는지를 정확히 정리하여 문서로 남겨야 한다.
→ 상속용 클래스는 재정의할 수 있는 메서드들을 내부적으로 어떻게 이용하는지(자기사용) 문서로 남겨야 한다.
- 공개된 메서드에서 클래스 자신의 또 다른 메서드를 호출하는데, 그 메서드가 재정의 가능 메서드인 경우
- 어떤 순서로 API를 호출해야 하는지
- 각각의 호출 결과가 이어지는 처리에 어떤 영향을 주는지
넓게 말하면, 재정의 가능 메서드를 호출할 수 있는 모든 상황을 문서로 남겨야 한다.
☑️ 상속용으로 설계한 클래스는 배포 전에 반드시 하위 클래스를 만들어 검증해야 한다
- 상속용 클래스를 시험하는 방법은 직접 하위 클래스를 만들어보는 것이 ‘유일’하기 때문
☑️ 상속용 클래스의 생성자는 직접적으로든 간접적으로든 재정의 가능 메서드를 호출해서는 안 된다
: 상위 클래스의 생성자가 하위 클래스의 생성자보다 먼저 실행되므로, 하위클래스에서 재정의한 메서드가 하위클래스의 생성자보다 먼저 호출됨
→ 재정의한 메서드가 하위클래스의 생성자에 의존한다면? → NullPointerException
- private ,final, static 메서드는 재정의가 불가하므로 생성자에서 호출 가능
- Clonable과 Serializable 인터페이스가 상속용 설계의 어려움을 더함
- 클래스를 상속용으로 설계하려면 엄청난 노력이 들고, 제약도 상당하다
☑️ 상속용으로 설계하지 않은 클래스는 상속을 금지하자
방법 1) 클래스를 final로 선언하기
방법 2) 모든 생성자를 private이나 package-private으로 선언하고 public 정적 팩터리 생성하기 (item17)
핵심 기능을 정의한 인터페이스가 있고, 클래스가 그 인터페이스를 구현했다면 상속을 금지해도 됨(Set, List, Map)
→ 이미 인터페이스가 필요한 기능들을 정의하고 있기 때문에, 상속을 통해 추가적인 기능을 물려받을 필요가 없기 때문
하지만 구체 클래스가 표준 인터페이스를 구현하지 않아서, 상속을 금지하면 사용하기 상당히 불편해지는 경우에는
→ 클래스 내부에선 재정의 가능 메서드를 사용하지 않게 만들고
→ 이 사실을 문서로 남기면 된다.
[핵심 정리]
- 상속용 클래스는 설계하기 어렵다.
- 모든 사용법을 문서로 남겨야 하며 반드시 지켜져야 하므로.
- 효율적인 하위클래스를 위해 일부 메서드를 protected로 제공해야 할 수도 있지만,
- 클래스를 확장할 명분이 없다면 상속을 금지하는게 낫다.
'Book > 이펙티브 자바' 카테고리의 다른 글
[Effective Java] item 20. 추상 클래스보다는 인터페이스를 우선하라 * (1) | 2023.12.18 |
---|---|
[Effective Java] item 18. 상속보다는 컴포지션을 사용하라 * (1) | 2023.10.06 |
[Effective Java] item 17. 변경 가능성을 최소화하라 (0) | 2023.10.04 |