Skip to content

Latest commit

 

History

History
72 lines (56 loc) · 3.61 KB

item19.md

File metadata and controls

72 lines (56 loc) · 3.61 KB

상속을 고려한 문서화


  • 메서드 재정의시 발생하는 일을 정확히 정리

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

  • 클래스의 API로 공개된 메서드에서 클래스 자신의 또 다른 메서드를 호출할 수도 있음

    • 호출되는 메서드가 재정의 가능 메서드라면, 그 사실을 호출하는 메서드의 API 설명에 적시
    • 어떤 순서로 호출하는지, 각각의 호출 결과가 이어지는 처리에 어떤 영향을 주는지 정리
    • ‘재정의 가능’: public, protected 메서드 중 final이 아닌 모든 메서드를 뜻함
    • 재정의 가능 메서드를 호출할 수 있는 모든 상황을 문서로 남겨야 함
      • ex) 백그라운드 스레드, 정적 초기화 과정에서도 호출이 일어날 수 있음
  • @implSpec 태그

    • API 문서의 메서드 설명 끝에 보이는 “Implementation Requirements”로 시작하는 절
    • 해당 메서드의 내부 동작 방식을 설명하는 곳임.
    • 해당 태그를 붙여주면 자바독 도구가 생성해준다
  • 이처럼 내부 메커니즘을 문서로 남기는 것만이 상속을 위한 설계의 전부는 아님

    • 클래스의 내부 동작 과정 중간에 끼어들 수 있는 훅(hook)을 잘 선별해 protected 메서드 형태로 공개
    • 어떤 메서드를 protected로 노출? → 잘 예측한 후 실제 하위 클래스를 만들어 시험해본다
    • 상속용으로 설계한 클래스는 배포 전에 반드시 하위 클래스를 만들어 검증해야 함
  • 상속용 클래스의 생성자는 직접적, 간접적 모두 재정의 가능 메서드를 호출하면 안된다.

    • 상위 클래스의 생성자가 하위 클래스의 생성자보다 먼저 실행되므로, 하위 클래스에서 재정의한 메서드가 하위 클래스의 생성자보다 먼저 호출된다.
    // 잘못된 예 - 생성자가 재정의 가능 메서드를 호출함
    
    // 상위 클래스 코드
    public class Super { 
    	public Super() {
    		overrideMe();
    	}
    
    	public void overrideMe() {
    	}
    }
    
    // 하위 클래스 코드
    
    public final class Sub extends Supper {
    	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();
    	}
    }
    • 위 코드는 instant를 두 번 출력하지 않고, 첫번째에서는 null을 출력함
      • 상위 클래스의 생성자는 하위 클래스의 생성자가 인스턴스 필드를 초기화하기도 전에 overrideMe를 호출하기 때문
  • 상속용으로 설계하지 않는 클래스는 상속을 금지한다.

    • 상속을 금지하는 방법
      1. 클래스를 final로 선언
      2. 모든 생성자를 private이나 package-private으로 선언 후 public 정적 팩터리를 만들어준다
  • 3줄 요약

    • 상속용 클래스를 설계하려면 클래스 내부에서의 자기사용 패턴을 모두 문서로 남겨야 하며, 문서화된 것은 그 클래스가 쓰이는 한 반드시 지켜져야 한다. 그렇지 않으면 하위 클래스들이 오동작한다.
    • 그러니 클래스를 확장해야 할 명확한 이유가 없다면 상속을 금지하는 편이 낫다.
    • 상속을 금지하려면 fina선언, 생성자 모두를 외부에서 접근할 수 없도록 만들면 된다.