아이템19. 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라
2021-10-18 00:00:00 # Effective_Java
  • 상속을 고려한 설계와 문서화?

  • 깊게는 생각하지 않고 넘어가자~

  • 상속용 클래스는 재정의할 수 있는 메서드들을 내부적으로 어떻게 이용하는지 문서로 남겨야 한다.

  • 재정의 가능 메서드를 호출할 수 있는 모든 상황을 문서로 남겨야 한다.

  • 좋은 API 문서란 ‘어떻게’가 아닌 ‘무엇’을 하는지를 설명해야 한다.

  • 클래스의 내부 동작 과정 중간에 끼어들 수 있는 훅(hook)을 잘 선별하여 protected 메서드 형태로 공개해야 할 수도 있다.

    • 드물게는 protected 필드로…

상속용 클래스를 시험하는 방법은 직접 하위 클래스를 만들어보는 것이 ‘유일’하다

  • 검증을 위해 하위 클래스 3개 정도가 적당하다.
  • 이 중 하나 이상은 제3자가 작성해봐야 한다.
  • 널리 쓰일 클래스를 상속용으로 설계한다면 문서화한 모든 내용을 영원히 책임져야 하며, 그 클래스의 성능과 기능에 영원한 족쇄가 될 수도 있다.
  • 상속용으로 설계한 클래스는 배포 전에 반드시 하위 클래스를 만들어 검증해야 한다.

상속용 클래스의 생성자는 직접적으로든 간접적으로든 재정의 가능 메서드를 호출해서는 안 된다

  • 프로그램 오동작 유발함
  • 상위 클래스의 생성자가 하위 클래스의 생성자보다 먼저 동작하기 때문에 하위 클래스에서 메서드를 재정의하기도 전에 동작해서 오동작한다.
  • private, final, static 메서드는 재정의가 불가능하니 생성자에서 안심하고 호출해도 된다.

clone과 readObject 모두 직접적/간접적으로든 재정의 가능 메서드를 호출하면 안 된다

  • readObject: 하위 클래스의 상태가 미처 다 역직렬화되기 전에 재정의한 메서드부터 호출하게 되어 오작동
  • clone: 하위 클래스의 clone 메서드가 복제본의 상태를 (올바른 상태로) 수정하기 전에 재정의한 메서드를 호출한다.
    • 완벽히 깊은 복제가 아니어서 원본 객체에 손을 댈 수도 있다.

상속용으로 설계하지 않은 클래스는 상속을 금지한다

  1. 클래스를 final로 선언해서 상속 막기
  2. 모든 생성자를 private이나 package-private으로 선언하고 public 정적 팩터리를 만들어주는 방법이다.

핵심 정리

  • 상속용 클래스를 설계하기란 결코 만만치 않다.
  • 클래스 내부에서 스스로를 어떻게 사용하는지(자기사용 패턴) 모두 문서로 남겨야 한다.
  • 문서화한 내용은 그 클래스가 쓰이는 한 반드시 지켜야 한다.
  • 그렇지 않으면 내부 구현 방식을 믿고 활용하던 하위 클래스를 오동작하게 만든다.
  • 클래스를 확장해야 할 명확한 이유가 떠오르지 않으면 상속을 금지하는 편이 낫다.