2011.04.18 20:58
  항목 16에서 상속을 위한 설계와 문서화를 하지 않은 클래스로부터 상속을 받을 때의 위험성을 경고하였다. 그렇다면 상속을 위한 설계와 문서화가 된 클래스란 무슨 의미일까?

 우선, 그런 클래스에서는 메소드 오버라이딩으로 인한 파급 효과를 분명하게 문서화해야 한다. 달리 말해 오버라이드 가능한 메소드들의 자체사용(self-use) 즉, 그 메소드들이 같은 클래스의 다른 메소드를 호출 하는지에 대해 반드시 문서화해야 한다.

 이와는 반대로, 각각의 public이나 protected 메소드 및 생성자가 어떤 오버라이드 가능한 메소드를 호출하는지, 어떤 순서로 하는지, 호출한 결과가 다음 처리에 어떤 영향을 주는지에 대해서도 반드시 문서화해야한다. 더 일반적으로 말하자면, 오버라이드 가능한 메소드를 호출 할 수 잇는 어떤 상황에 대해서도 문서화해야 한다는 것이다. 
  
 관례적으로 오버라이드 가능한 메소드를 호출하는 메소드에는 문서화 주석의 제일 끝에 그런 호출에 대한 설명을 추가한다. 그리고 설명의 시작은 "이번 구현 버전(This implementation)"이라는 구문으로 한다. 배포판이 달라지면서 메소드의 동작이 변경될 수 있다는 것을 나타내기 위해서만 그런 구문을 넣어서는 안된다. 그 구문에서는 메소드 내부에서 처리하는 작업에 관련되는 설명을 담고 있어야 한다. 

 책에서는 java.util.AbstractCollection의 명세를 예로 들고 있다. 참고하기를 바란다.

 그러나 잘된 API 문서에는 메소드가 무슨(what) 일을 하는지 기술해야 하고,   어떻게(how) 하는지를 설명하면 안된다는 통념을 어기는 것이다.
  이것은 결국 상속이 캡슐화를 위반함으로써  초래된 불행인 것이다. 서브 클래스가 안전할 수 있게끔 클래스를 문서화하려면, 클래스의 상세 구현 내역을 기술해야 한다(보통때는 하지 않지만).

 오버라이드 가능한 메소드들이 같은 클래스의 다른 메소드를 호출하는 자체 사용을 문서화 하는것 이외에도 상속을 위한 클래스 설계에는 고려할 점이 많다. 그 중 하나로써 잘 선정된 protected 메소드(또는 드물지만 protected 필드)를 제공하여 클래스 내부의 다른 메소드와 연결되도록 해야 한다.
 또한 상속 관련해서 특별히 추가되는 내용과 일반적인 내용(평범하게 클래스 인스턴스를 생성하고 메소드를 호출하는 프로그래머를 위한)이 섞임으로 API 문서를 보기가 혼란스러워 질 수 있다는것에 유의하자.

 상속을 허용하기 위해 클래스가 준수해야 하는 제약이 몇가지 더 있다. 직접 또는 간접의 어떤 형태로든 생성자에서는 오버라이드 가능한 메소드를 호출하면 안된다.

 상속을 위한 클래스를 테스트하는 유일한 방법은 서브 클래스를 만들어 보는것이다.
 그리고 그 서브클래스는 수퍼클래스 작성자가 아닌 사람이 작성해야 한다.



 상속을 위한 클래스 설계에서 Cloneable과 Serializable 인터페이스 중 어느 하나를 구현하는 상속을 위한 클래스를 설계하는 것은좋은 생각이 아니다.(textbook 항목 11과 74 참조)
 꼭 구현해야겠다면 clone과 readObject 메소드가 생성자와 흡사하게 동작하므로 생성자와 유사한 규칙이 적용된다는 것에 유의해야 한다. 즉, 직접 또는 간접의 어떤 형태로든 clone이나 readObject 모두 오버라이딩 가능한 메소드를 호출하면 안된다.
 마지막으로, 상속을 위해 설계된 클래스가 Serializable 인터페이스를 구현하기로 했는데, 그 클래스가 readResolve나 writeReplace 메소드를 가지고 있다면, 그 메소드들을 private가 아닌 protected로 해야한다. 만일 그 메소드들이 private라면 서브 클래스에서 사용할 수 없기 때문이다. 상속을 허용하기 위해 클래스 내부의 구현 메소드가 그 클래스의 API가 되어야 하는 것이다.



 많은 논점이 있었지만 중요한 것은 상속을 위해 클래스를 설게하다 보면 그 클래스에 많은 제약이 생긴다. 라는것이다. 서브 클래스를 안전하게 만들수 있도록 설계나 문서화를 제공하지 않는 클래스의 상속을 금지하는 것이 좋은 방법이라고 할 수 있겠다.
 금지하는 방법은 클래스를 final로 선언하거나, 생성자를 private 혹은 default로 두고 public static 팩토리 메소드를 추가하는것이다.(항목15)

 하지만 실제 프로그래밍에서는 실체 클래스에서 상속을 사용하는 일이 많을 것이므로 이럴 경우에는 항목 16에서 설명한 래퍼 클래스를 만들거나 어떤 오버라이드 가능한 메소드의 자체 사용(self-use)를 완전히 없애는 방법도 있다. 또는 오버라이드 가능한 메소드의 몸체코드를 private "지원(helper)메소드"로 옮기고, 오버라이드 가능한 메소드에서는 그 지원 메소드를 호출하도록 하는 방법도 있다.




 
신고
Posted by JAVA_HOME

댓글을 달아 주세요


티스토리 툴바