Item19. 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라
상속용 클래스의 문서화
- 상속용 클래스는 overriding할 수 있는 method들을 내부적으로 어떻게 이용하는 지 문서로 남겨야 한다.
- 클래스의 API로 공개된 method에서 클래스 자신의 또 다른 method를 호출할 수도 있는데, 이 method가 overriding이 가능하다면 method의 API 설명에 적어두어야 한다.
- 어떤순서로 호출되는지, 호출 결과가 이어지는 처리에 어떤 영향을 줄 수 있는지도 문서화해야한다.
문서화 예시 : https://docs.oracle.com/javase/7/docs/api/java/util/AbstractCollection.html
API 문서의 method설명 끝에서 종종 ‘This Implementation’ ~ 로 시작하는 절을 볼 수 있는데 이 부분이 method의 내부 동작 방식을 설명하는 곳이다.
클래스를 안전하게 상속할 수 있도록 하려면, 내부 구현 방식에 대해 설명해주어야 한다.
( Java method 주석에 @implSpec tag를 붙여주면 자바독 도구가 생성해준다. )
상속용 클래스의 제약
- 상속용 클래스의 생성자는 overriding 가능한 method를 호출해서는 안된다.
(private,final,static method는 overriding이 불가능하니 생성자에서 호출하여도 무관하다. )
1 | public class Super { |
Super라고 하는 상위 class에서 생성자에 overriding가능한 method를 호출한 상황을 가정하자
1 | public final class Sub extends Super{ |
Super class를 상속한 자식 class에서 부모 생성자를 호출 -> 부모 생성자에서 overrideMe() 호출 -> 자식class의 instant 필드는 초기화 되기전임으로 null 출력이 된다.
- clone과 readObject 모두 overriding 가능한 method를 호출해서는 안된다.
예를 들어 , clone과 readObject는 객체를 새로 만드는 데 중간에 overriding 한 method를 호출한 경우, 제대로 복사되지 않은 객체가 만들어질수 있다.
1 | public class Parent implements Cloneable{ |
1 | public final class Child extends Parent { |
1 | public static void main(String[] args) { |
특히 clone이 잘못되면 복제본 뿐 아니라 원복객체에도 피해를 줄 수 있다, 가변필드는 복제본이랑 원본과 공유되고 있는 상태를 예시로 들 수 있을 것이다.
- Serializable 을 구현한 상속용 class가 readResolve 나 writeReplace method를 갖는다면 이 method들은 private 가 아닌 protected 로 선언해야 한다.
- readResolve : 역직렬화 과정에서 호출되는 method
- writeReplace : 직렬화된 상태에서 다시 객체로 만들떄 호출되는 method
private 로 선언한다면 하위 class에서 무시되기 떄문이다.
일반적인 구체 클래스
상속용으로 만들지 않고, 문서화되지 않은 class는 개발할떄 필요에 의해서 상속해도 괜찮을까? 되도록이면 상속을 금지하고, 대신 핵심 기능들을 정의해놓은 인터페이스 구현을 하는 것을 권고하고 있다.
상속을 금지하는 방법은 이전 item에서도 다루었듯이 class를 final로 선언하거나 생성자를 하위class에서 호출할수 없도록 막는 방법이 있다.
- 꼭 상속을 해야 한다면, 상속할 class 내부에 overriding 가능한 method들을 호출하는 코드가 없도록 하고, 이를 문서화 해야한다.
1 | public void doSomething(){ |
overriding 가능한 자기 사용 코드를 완벽히 제거하면, method를 자식 class에서 overriding해도 다른 method와는 독립적으로 작동할수 있으므로, 안전하다.
정리
상속용 class를 설계하려면 내부동작 방식과 다른 method들을 어떻게 호출하는지 (자기 사용 패턴) 을 모두 문서화해야 하며, 한번 문서화하면 변경하면 안된다. 때문에 상속을 사용해야할 명확할 이유가 없다면 상속을 금지하는 것을 권고한다.