상속은 코드를 재사용하는 강력한 수단이지만, 항상 최선은 아니다. 일반적인 구체 클래스를 패키지 경계를 넘어 다른 패키지의 구체 클래스를 상속하는 일은 위험하다.
상속이 안전 할 때
상속이 안전하지 않을때
다른 패키지의 구체 클래스를 상속하는 것은 위험하다.
하위 클래스가 깨지기 쉬워 상속은 캡슐화를 깨뜨린다.
상위클래스의 구현에 따라 하위 클래스의 동작에 이상이 생길 수 있다.
상위클래스는 릴리스(업데이트)마다 내부 구현이 달라질 수 있으며, 그 여파로 하위 클래스가 오동작, 그리고 귀찮게 수정을 해야한다.
바로 컴포지션!
컴포지션
: 기존 클래스가 새로운 클래스의 구성요소로 쓰인다.
기존 클래스를 확장하는 대신, 새로운 클래스를 만들고 private 필드로 기존 클래스의 인스턴스를 참조하게 하면 된다.
(composition; 구성)
이라 한다.상속의 취약점을 피하려면 상속 대신 컴포지션과 전달을 사용한다.
특히 래퍼 클래스로 구현할 적당한 인터페이스가 있다면 더욱 그렇다. 래퍼 클래스는 하위 클래스보다 견고하고 강력하다.
하위 클래스가 상위 클래스의 '진짜' 하위 타입인 상황에서만 쓰자. 클래스간 관계가 is-a
관계일때만 상속하자.
컴포지션을 사용해야할 상황에서 상속을 사용하는 건 내부 구현을 불필요하게 노출하는 것이다.
결론) 컴포지션으로는 이런 결함을 숨길 수 있지만, 상속은 아니다.
이펙티브 자바, 저 조슈아 블로크