[Effective Java] item19 - 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라

신민철·2023년 4월 30일
1

Effective Java

목록 보기
19/23
post-thumbnail

평소에 개발할 때 상속을 하여 개발할 일이 많을 것이다. 근데 이러한 상속하는 과정에서 다양한 것을 고려하지 않으면 에러가 발생할 수 있다. 한번 알아보자.

먼저, 문서화를 해야 한다!

상속을 할 때는 많은 경우에 메소드를 재정의하게 되는데, 이런 경우 특정 메소드에서 재정의 가능한 메소드를 호출할 때 내부적으로 버그가 생길 수 있다! 그래서 이러한 것들을 내부적으로 어떻게 이용하는지 문서로 남겨야 한다. 내부 순서와 그것들은 어떤 결과로 이어지는지 명시되어 있으면 더더욱 좋다.

Implementation Requirements: This implementation iterates over the collection looking for the specified element. If it finds the element, it removes the element from the collection using the iterator's remove method. Note that this implementation throws an UnsupportedOperationException if the iterator returned by this collection's iterator method does not implement the remove method and this collection contains the specified object.

Implementation Requirements는 메소드 내부 동작을 설명하는 곳이다. @ImplSpec 어노테이션을 붙이면 자바독 도구가 생성해준다.

굉장히 귀찮아보이는데 왜 작성할까? 상속이 캡슐화를 해치기 때문에 내부 동작 과정을 설명해야 하는 것이다.

다음은 클래스의 내부 동작 중간에 끼어들 수 있는 메소드(혹은 필드)를 잘 구별하여 protected 형태로 공개해야 할 수도 있다. 예시로는 AbstractList.removeRange() 의 경우 특정 상황에서 clear()의 성능을 향상시키려면 사용하는 것이 좋은 경우가 있다.

이런 것들을 protected로 공개해야 할텐데 어떤 기준으로 공개해야 할까? 결국에는 테스트가 최선이다..

상속용 클래스를 시험하는 방법은 직접 하위 클래스를 만들어보는 것이 ‘유일’하다.

일반적으로 이런 검증은 최소 3번이 필요하고 1번 이상은 제 3자가 작성하는 것이 좋다.

이런 것들을 잘 테스트해야 나중에 구현된 내용들이 족쇄가 되지 않을 수 있다. 그래서 상속용으로 설계한 클래스는 배포 전에 반드시 하위 클래스를 만들어 검증해야 한다.

다음으로는 상속용 클래스의 생성자는 재정의 가능한 메소드를 호출해서는 안된다.

앞서 나왔던 내용인 Cloneable과 Serializable 인터페이스는 상속의 어려움을 한층 끌어올려준다. Cloneable은 앞의 아이템에서 느꼈을 것이고 Serializable은 readObject가 생성자와 비슷한 제약이 있기 때문에 재정의 가능한 메소드를 사용하면 안된다!

일반적인 구체 클래스는 final도 아니고 상속용으로 설계되지도 않고 문서화되지도 않는다. 그러면 클래스의 변화가 생길 때마다 하위 클래스들은 오동작을 일으킬 가능성이 높을 것이다. 이것의 해결 방법은 단순하게 상속용으로 설계하지 않았으면 상속을 금지하는 것이다. 전에 배웠던 생성자를 private, package-private으로 생성하고 public 정적 팩토리를 만들어서 제공하는 방법이다.

그런데, 구체 클래스가 표준 인터페이스를 구현하지 않았는데 상속을 막으면 굉장히 불편할 것이다. 클래스 내부에 재정의 가능한 메소드를 사용하지 않게 만들고 이를 문서화하면 비교적 안전하게 상속을 수행할 수 있게 된다.

핵심 정리
상속을 단순하게 여겨서는 안된다. 상속을 하려면 내부 프로세스를 문서화하여 공개해야 한다. 그리고 효율을 극대화하기 위해서는 때때로 protected 메소드를 공개해야 할 것이다. 상속의 당위성이 없다면 하지 않는 것이 좋고 상속을 금지하려면 private 생성자를 두거나 final로 선언하면 될 것이다.

0개의 댓글