티스토리 뷰

반응형

상속을 고려한 설계와 문서화

1) 메서드를 재정의할때 어떤일이 일어나는지 정확히 정리하여 문서로 남겨라.
상속용 클래스는 재정의할 수 있는 메서드(public, protected 이면서 final이 아닌 메서드)들을 내부적으로 어떻게 이용하는지 문서로 남겨야 한다.

 

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

 

3) 상속용으로 설계한 클래스를 시험하는 방법은 직접 하위 클래스를 만들어보는 것이다.

꼭 필요한 protected 멤버를 놓쳤다면 빈 자리가 드러남, 전혀 쓰이지 않는 protected 멤버는 사실 private 임 등을 알 수 있다. 배포전에 반드시 하위 클래스를 만들어 검증해봐야한다.

 

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

상위 클래스의 생성자가 하위 클래스의 생성자보다 먼저 실행되기 때문에 하위 클래스에서 재정의한 메서드가 하위 클래스의 생성자보다 먼저 호출됨 → 이 때 하위 클래스의 생성자에서 초기화하는 값에 의존한다면 의도대로 동작하지 않는 오류!

public class Super {
    // 잘못된 예시 - 생성자가 재정의 가능 메서드를 호출한다.
    public Super() {
        overrideMe();
    }

    public void overriedMe() {

    }
}
public final class Sub extends Super {
    // 초기화되지 않은 final 필드, 생성자에서 초기화한다.
    private final Instant instant;

    Sub() {
        instant = Instant.now();
    }

    // 재정의 가능 메서드, 상위 클래스의 생성자가 호출한다.
    @Override public void overrideMe() {
        System.out.println(instant);
    }

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

처음에 null을 출력하게 된다.

private, final, static 메서드는 재정의가 불가능하니까 생성자에서 호출해도 된다.

 

5) clone과 readObject 는 직접적으로든 간접적으로든 재정의 가능 메서드를 호출해서는 안된다.

상속용 클래스에서 Cloneable이나 Serializable을 구현해야 한다면, 이 때 제약이 생성자와 비슷하다.

readObject의 경우 하위 클래스의 상태가 다 역직렬화되기 전에 재정의한 메서드부터 호출하는 문제가 생긴다.

clone의 경우 하위 클래스의 clone 메서드가 복제본의 상태를 수정하기 전에 재정의한 메서드를 호출하는 문제가 생긴다.

 

6) Serializable을 구현한 상속용 클래스가 readResolve나 writeReplace 메서드를 갖는다면 이 메서드들은 private이 아닌 protected로 선언해야한다. private는 하위 클래스에서 무시된다.

 

 

상속을 금지하는 방법

상속용으로 설계하지 않은 클래스는 상속을 금지하는 것이 좋다.

  • final 클래스
  • 모든 생성자를 private 이나 package-private 으로 선언하고 public 정적 팩터리를 만든다.

상속을 금지하고 래퍼 클래스 패턴을 사용하는것이 좋다.

상속을 사용해야한다면, 재정의 가능 메서드를 호출하는 자기 사용 코드를 제거하고 문서로 남겨라.

 

클래스의 동작을 유지하면서 재정의 가능 메서드 사용하는 방법

: 각각의 재정의 가능 메서드는 자신의 본문 코드를 private 도우미 메서드로 옮긴다 → 이 도우미 메서드를 호출하도록 수정 → 재정의 가능 메서드를 호출하는 다른 코드들도 모두 이 메서드를 직접 호출하도록 변경

 

 

결론

상속용 클래스를 설계하기 위해선 자기 사용 패턴을 모두 문서로 남겨야 하고 지켜야 한다.

그렇지 않으면, 하위 클래스에서 오동작이 발생한다.

클래스를 확장해야할 명확한 이유가 없다면 상속을 금지해라.(final / 생성자 접근 금지)

반응형
댓글
반응형
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday