# 아이템19 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라

`상속용 클래스`는 재정의할 수 있는 메서드들을 내부적으로 어떻게 이용하는지(`자기사용`) 문서로 남겨야 한다. 덧붙여서 `어떤 순서로 호출`하는지, 각각의 호출 결과가 이어지는 처리에 `어떤 영향`을 주는지도 담아야 한다.

하지만 이런 식은 "`좋은 API 문서란 '어떻게'가 아닌 '무엇'을 하는지를 설명해야 한다`"라는 격언 과는 대치되지 않나? 그렇다. 상속이 `캡슐화`를 해치기 때문에 일어나는 안타까운 현실이다.

`@implSpec` 태그는 `자바 8`에서 처음 도입되어 자바 9부터 본격적으로 사용 되기 시작했다.

효율적인 하위 클래스를 큰 어려움 없이 만들 수 있게 하려면 클래스의 내부 동작 과정 중간에 끼어들 수 있는 `훅(hook)`을 잘 선별하여 `protected` 메서드 형태로 공개해야 할 수도 있다.

java.util.AbstractList의 removeTange 메서드를 예로 살펴보자

```
protected void removeRange(int fromIndex, int toIndex)

...
 이 리스트는 혹은 이 리스트의 부분리스트에 정의된 clear 연산이 이 메서드를 호출한다. 
```

List 구현체의 최종 사용자는 `removeRange` 메서드에 관심이 없다. 그럼에도 이 메서드를 제공한 이유는 단지 하위 클래스에서 부분리스트의 `clear` 메서드를 고성능으로 만들기 쉽게 하기 위해서다. removeRange 메서드가 없다면 하위 클래스에서 clear 메서드를 호출하면 제곱에 비례해 성능이 느려지거나 부분리스트의 메커니즘을 밑바닥부터 새로 구현해야 했을 것이다.

### 그렇다면 상속용 클래스를 설계할 때 어떤 메서드를 protected로 노출해야 할지는 어떻게 결정할까?

정답은 없다. 심사숙고해서 잘 `예측`해본 다음, 실제 하위 클래스를 만들어 시험 해보는 것이 최선이다.

상속용 클래스를 시험하는 방법은 직접 하위 클래스를 만들어보는 것이 '`유일`'하다. 꼭 필요한 protected 멤버를 놓쳤다면 하위 클래스를 작성할 때 그 빈자리가 확연히 드러난다. 거꾸로, 하위 클래스를 여러 개 만들 때까지 전혀 쓰이지 않는 protected 멤버는 사실 `private` 이여야 할 가능성이 크다.

### 상속용으로 설계한 클래스는 배포 전에 반드시 하위 클래스를 만들어 검증해야 한다.

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

```
public class Super {
    public Super() {
        overrideMe();
    }

    public void overrideMe() { ... }
}

public final class Sub extends Super {
    Sub() {
        instant = Instant.now();
    }

    @Override
    public void overrideMe() {
        System.out.println(instant);
    }

    public static void main(String[] args) {
        Sub sub = new Sub();
        sub.overrideMe();
    }
}
```

이 프로그램이 instant를 두 번 출력하리라 기대했겠지만, 첫 번째는 `null`을 출력한다. 상위 클래스의 생성자는 하위 클래스의 생성자가 인스턴스 필드를 초기화하기도 전에 `overrideMe`를 호출하기 때문이다.

`clone`과 `readObject` 메서드는 생성자와 비슷한 효과를 낸다. 따라서 상속용 클래스에서 Cloneable이나 Serializable을 구현할지 정해야 한다면, 이들을 구현할 때 따르는 제약도 생성자와 비슷하다는 점에 주의하자. 즉, clone과 readObject 모두 직접적으로든 간접적으로든 재정의 가능 메서드를 호출해서는 안 된다.

마지막으로, `Serializable`을 구현한 상속용 클래스가 `readResolve`나 `writeReplace` 메서드를 갖는다면 이 메서드들은 private이 아닌 `protected`로 선언해야 한다. private으로 선언한다면 하위 클래스에서 무시되기 때문이다. 이 역시 상속을 허용하기 위해 내부 구현을 클래스 API로 공개하는 예 중 하나다.

### 그렇다면 그 외의 일반적인 구체 클래스는 어떨까?

전통적으로 이런 클래스는 final도 아니고 상속용으로 설계되거나 문서화되지도 않았다.

이 문제를 해결하는 가장 좋은 방법은 상속용으로 설계하지 않은 클래스는 상속을 `금지`하는 것이다. 상속을 금지하는 방법은 클래스를 `final`로 선언하는 방법이다. 또는 모든 생성자를 `private`이나 `package-private`으로 선언하고 `public 정적 팩터리`를 만들어주는 방법이다.

구체 클래스가 표준 인터페이스를 구현하지 않았는데 상속을 금지하면 사용하기에 상당히 불편해진다. 이런 클래스라도 상속을 꼭 허용 해야겠다면 합당한 방법이 하나 있다. 클래스 내부에서는 `재정의 가능 메서드`를 사용하지 않게 만들고 이 사실을 `문서`로 남기는 것이다. 재정의 가능 메서드를 호출하는 `자기 사용 코드`를 완벽히 `제거`하라는 말이다.

클래스의 동작을 유지하면서 재정의 가능 메서드를 사용하는 코드를 제거할 수 있는 기계적인 방법을 소개한다. 먼저 각각의 재정의 가능 메서드는 자신의 본문 코드를 private '`도우미 메서드`'로 옮기고 이 도우미 메서드를 호출하도록 수정한다. 그런 다음 재정의 가능 메서드를 호출하는 다른 코드들도 모두 이 도우미 메서드를 직접 호출하도록 수정하면 된다.

> 도우미 메서드를 이용한 사례는 어떤게 있을까?

## 정리

`상속용 클래스`를 설계 하기란 결코 만만치 않다. 클래스 내부에서 스스로를 어떻게 사용하는지(`자기사용 패턴`) 모두 문서로 남겨야 하며, 일단 `문서화`한 것은 그 클래스가 쓰이는 한 반드시 지켜야 한다. 그러지 않으면 그 내부 구현 방식을 믿고 활용하던 하위 클래스를 `오동작`하게 만들 수 있다. 다른 이가 효율 좋은 하위 클래스를 만들 수 있도록 일부 메서드를 `protected`로 제공해야 할 수도 있다. 그러니 클래스를 확장해야 할 명확한 이유가 떠오르지 않으면 `상속을 금지`하는 편이 나을 것이다. 상속을 금지하려면 클래스를 `final`로 선언하거나 `생성자` 모두를 외부에서 접근할 수 없도록 만들면 된다.
