19. 상속을 고려해 설계하고 문서화하라. 그렇지 않았다면 상속을 금지하라

신명철·2022년 2월 18일
0

Effective Java

목록 보기
17/80

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

protected 메서드

내부 매커니즘을 문서로 남기는 것만이 상속을 위한 설계의 전부는 아니다. 효율적인 하위 클래스를 큰 어려움 없이 만들 수 있게 하려면 클래스의 내부 동작 과정 중 끼어들 수 있는 훅(hook)을 잘 선별해서 protected 메서드 형태로 공개해야 할 수도 있다.

어떤 메서드를 protected로 노출할 지는 심사숙고해서 잘 결정한 후 하위 클래스를 만들어 테스트를 해보자. 다만 protected 메서드는 내부 구현이므로 그 수는 가능한 한 적어야 한다.

상속용 클래스 테스트

상속용 클래스를 테스트하는 방법은 직접 하위 테스트를 만들어 보는 것이 유일하다. 꼭 필요한 protected 멤버를 놓쳤다면 하위 클래스를 작성할 때 그 빈자리가 확연히 드러난다.

상속용 클래스의 생성자

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

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

public final class Sub extends Super {
	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();
	}
}

상위 클래스의 생서자는 하위 클래스의 생성자보다 먼저 실행되기 때문에 하위 클래스에서 재정의한 메서드가 하위 클래스의 생성자보다 먼저 호출된다.

Cloneable & Serializable

Cloneable 과 Serializable 를 상속한 클래스를 상속하는 것은 더 어려운 일이다. readObject 의 경우 하위 클래스의 상태가 미처 다 역직렬화 되기 전에 재정의한 메서드부터 호출한다. clone 의 경우 하위 클래스의 clone 메서드가 복제 본의 상태를 수정하기 전에 재정의한 메서드를 호출한다. 이는 직접적으로든 간접적으로든 재정의 가능 메서드를 호출하지 마라는 제약에 걸린다.

비상속 클래스

상속은 캡슐화를 깨뜨릴 수 있는 문제가 있다. 그렇다면 상속용으로 설계하지 않은 클래스의 상속은 어떻게 막아야 할까? 가장 좋은 방법은 상속을 금지시키는 것이다. 두 가지 방안이 있다.
첫째는, 클래스를 final 로 선언하는 방법이다. 둘째는, 모든 생성자를 private 나 package-private로 선언하고 public 정적 팩터리 메서드를 만들어주는 방법이다.

핵심 기능을 정의한 인터페이스와 구체 클래스가 이 인터페이스를 확장했다면 상속을 금지해도 어려움이 없다. 하지만, 표준 인터페이스를 구현하지 않았는데 상속을 금지했다면 사용이 불편해진다. 이럴때는 클래스 내부에서 재정의 가능 메서드를 사용하지 않게 만들고 이 사실을 문서로 남기면 된다.

public class A{
	public A(){};
	
    public void OverrideMethod(){
    	OverrideHelperMethod();
    }
    private void OverrideHelperMethod(){
    	...(OverridMethod() 였던 것)
    }
}
public class A extends B{
    public B(){
    }
	
    @Override
    public void OverrideMethod(){
    }
}

클래스의 동작을 유지하면서 재정의 가능 메서드를 사용하는 코드를 제거할 수 있는 기계적인 방법은 다음과 같다.

  1. 재정의 가능 메서드는 자신의 본문 코드를 private '도우미 메서드'로 옮긴다.
  2. 재정의 가능 메서드를 호출하는 다른 코드들도 모두 이 '도우미 메서드'를 호출하도록 수정한다.
profile
내 머릿속 지우개

0개의 댓글