외부 패키지에 있는 구체 클래스를 상속하는 일은 위험하다. 통제권 밖에 있는 클래스는 언제 어떻게 변경될지 모르기 때문이다. 자식클래스는 부모클래스의 영향을 받을 수 밖에 없다.
메소드 호출과 달리 상속은 캡슐화를 깨뜨린다. 상위 클래스의 구현에 따라 하위 클래스가 위험해질 수 있다. 그러므로 상속은 반드시 is-a 관계일 때만, 진짜 하위타입인 경우에만 사용해야 한다.
특정한 기능을 하는 Set 클래스(새로운 클래스)가 직접 HashSet을 상속하기 보다는 HashSet을 새로운 클래스의 멤버변수로 구성하는 것이 더 좋은 접근 방식이다. 새로운 클래스는 HashSet의 모든 정보가 필요없는데, 상속을 하게 되면 불필요하게 모든 내부 구현을 새로운 클래스에 노출하게 된다. 그러므로 특정한 기능만 필요한 경우에는 상속이 아니라 컴포지션을 사용한다.
아이템 19 상속을 고려하여 설계하고 문서화 하라. 그러지 않았다면 상속을 금지하라
자식클래스에서 재정의 가능성이 높은 메소드는 부모 클래스(상속용클래스)가 내부로직이 어떻게 구현되어 있는지 문서화해야 한다. 상속은 캡슐화를 해치기에, 클래스를 안전하게 상속하려면 내부 구현방식을 설명해야 한다. 내부 구현과정에서 사용되는 훅(hook)은 외부에 있는 자식클래스도 접근이 가능하도록 protected 메소드로 선언해야 할 수 있다. 자식 클래스가 재정의 하는 과정에서 훅을 이용한 구현이 가능해야 하기 때문이다. ( 빼거나 넣거나 )
상속용 클래스를 테스트하는 방법은 하위클래스를 직접 만들어 보는 방법밖에 없다.
부모클래스(상속용 클래스)의 생성자는 재정의 가능한 메서드를 호출하면 안된다. 부모가 생성되기 전에 재정의된 자식 메서드가 먼저 실행되기 때문이다. 자식 메서드가 부모의 필드를 참조한다면 오류가 발생한다.
상속용으로 설계하지 않은 구체 클래스는 상속이 불가능하도록 미리 방지하는 것이 좋다.
1) 모든 생성자를 private, package-private으로 선언한다.
2) public 정적 팩터리를 만들어준다.
3) 클래스를 final로 선언한다.
하지만 이는 논란을 일으킬 수 있다. 구체 클래스를 굳이 상속용으로 써야하는 상황이 있기 때문이다.
1) 재정의 가능 메서드를 선별한다.
2) 재정의 가능 메서드를 클래스 내부 메소드가 호출하지 않도록 문서화 한다.
재정의 가능 메서드를 호출하지 않도록 강제하려면 재정의 가능 메서드의 본문을 똑같이 가지고 있는 도우미 메서드를 만들고 private으로 선언하여 자식 클래스가 사용하지 못하도록 막는다. 그리고 그것을 호출하여 사용한다.
'Dev > JAVA' 카테고리의 다른 글
[Effective JAVA] 추상클래스보다는 인터페이스를 우선하라 (아이템20) (0) | 2024.03.21 |
---|---|
[Effective JAVA] 변경가능성을 최소화 하라. ( 아이템 17 ) (0) | 2024.03.21 |
[Effective JAVA] 클래스와 멤버의 접근권한을 최소화하라. ( 아이템15 ) (0) | 2024.03.20 |
[Effective JAVA] 불필요한 객체 생성을 피하라 ( 아이템6 ) (0) | 2024.03.20 |
[Effective JAVA] 자원을 직접 명시하지 말고 의존객체 주입을 사용하라. ( 아이템5 ) (0) | 2024.03.20 |