본문으로 바로가기

1. 상속의 문서화

상속을 염두하지 않고 설계했으며 상속의 주의점을 문서화하지 않은 외부(개발자에게 통제권이 없는) 클래스를 상속하는 것은 위험하다. 상속용 클래스는 오버라이드 할 수 있는 메서드들을 내부적으로 어떻게 이용하는지(자기사용) 문서로 남겨야 한다.

 

  • 오버라이드할 수 있는 메서드란 final이 아닌 public 혹은 protected 메서드이다.
  • 재정의 가능 메서드를 호출할 수 있는 모든 상황을 명시해야 한다.

    • API 문서의Implementation Requirements로 시작하는 절이 해당 상황을 명시한다.

    • XX 메서드를 재정의하면 YY 메서드를 사용하는데 영향을 끼칠 수 있다 등의 내용이다.

단순히 내부 매커니즘을 문서화하는 것이 아니라, 효율적인 하위 클래스 제작을 위해 클래스의 내부 동작 과정 중 끼어드는 훅(Hook)을 선별하여 protected 메서드로 공개해야 할 수도 있다.

 

  • List는 원소를 비우는clear()메서드를 제공하지만removeRange()protected 메서드를 별도로 제공한다.

    • 하위 클래스에서 부분 리스트의clear()메서드를 고성능으로 만들기 위함이다.

문서화한 내용은 해당 클래스가 쓰이는 한 반드시 지켜져야 한다. 그렇지 않으면 내부 구현 방식을 믿고 활용하던 하위 클래스가 오작동할 수 있다.

2. 주의 사항

상속용으로 설계한 클래스는 배포 전에 하위 클래스를 만들어서 점검하라.

 

  • 어떤 메서드와 필드를 protected로 공개할지 등과 관련된 정답은 없다.
  • protected로 공개된 내부 구현은 클래스의 성능과 기능에 영원히 영향을 끼치기 때문에 잘 고려해야 한다.

    • protected가 너무 적으면 상속의 이점이 없다.

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

 

  • 하위 클래스의 인스턴스가 초기화되기 이전에super()생성자에서 재정의 가능한 메서드를 호출하면 NPE 등 원하지 않는 결과가 발생할 수 있다.

Cloneable과 Serializable 인터페이스를 구현한 클래스는 가급적 상속용으로 설계하지 않는다.

 

  • clone()과readObject()역시 직접적이든 간접적이든 재정의 가능 메서드를 호출해서는 안 된다.
  • 복제본이 완전히 수정되기 전 및 클래스가 완전히 역직렬화 되기 전에 호출되어 오작동이 날 수 있다.

상속이 필요 없는 일반 구체 클래스는 상속을 금지하라.

 

  • 상위 클래스에 변화가 생길 때 마다 하위 클래스를 오작동시킬 수 있다.
  • final을 명시하거나 생성자를 private 혹은 package-private으로 수정하고 정적 팩토리 메서드를 제공하라.

상속을 허용하려거든 내부에서 재정의 가능한 메서드를 자기사용하지 않게 만들고 문서화하라.

 

  • 하위 클래스에서 메서드를 재정의해도 다른 메서드에 영향을 주지 않는 등 위험도가 떨어진다.

Helper 메서드를 통해 재정의 가능 메서드를 사용하는 코드를 제거할 수 있다.

 

  • 클래스의 동작을 유지하면서 재정의 가능 메서드를 사용하는 코드를 제거할 수 있다.
  • 재정의 메서드는 자신의 본문 코드를 private Helper 메서드에 옮기고, 해당 Helper 메서드를 호출하도록 한다.
  • 이후, 재정의 가능 메서드를 호출하는 모든 코드들이 Helper 메서드를 호출하도록 한다.

요약

상속용 클래스를 설계하기란 결코 만만치 않다. 클래스 내부에서 스스로를 어떻게 사용하는지 모두 문서로 남겨야 하며

일단 문서화한 것은 쓰이는 한 반드시 지켜야 한다.

 

그러지 않으면 그 내부 구현 방식을 믿고 활용하던 하위 클래스를 오동작하게 만들 수 있다.

다른 이가 효율 좋은 하위 클래스를 만들 수 있도록 일부 메서드를 protected로 제공해야 할 수도 있다.

 

그러니 클래스를 확정해야 할 명확한 이유가 떠오르지 않으면 상속을 금지하는 편이 나을 것이다.

상속을 금지하려면 클래스를 final로 선언하거나 생성자를 모두를 외부에서 접근할 수 없도록 만들면 된다.