Effective Java 2판 - 4장 정리 (Class, Interface)

 

규칙 13: 클래스와 멤버의 접근 권한은 최소화하라.

정보 은닉과 캡슐화를 통해 모듈의 재사용성을 높이고 병렬적인 개발을 가능하게 하자. 그것의 기초는 각 클래스와 멤버는 가능한 한 접근 불가능하도록 만드는 것이다.

 

1.     객체 필드는 절대로 public으로 선언하면 안 된다. 필드에 저장될 값을 제한할 수 없고 다중 스레드에 안전하지 않다.

2.     길이가 0이 아닌 배열은 언제나 변경 가능하므로 배열 필드를 반환하는 접근자를 정의하면 안 된다.

 

규칙 14: public 클래스 안에는 public 필드를 두지 말고 접근자 메서드를 사용하라.

 

규칙 15: 변경 가능성을 최소화해라.

변경 불가능 클래스를 지향해라. 아래의 다섯 규칙을 따르면 된다.

  1. 객체 상태를 변경하는 메서드를 제공하지 않는다.
  2. 상속할 수 없도록 한다.
  3. 모든 필드를 final로 선언 한다.
  4. 모든 필드를 private으로 선언한다.
  5. 변경 가능한 컴포넌트에 대한 독점적 접근권을 보장한다: 클래스에 포함된 변경 가능 객체에 대한 참조를 클라이언트는 획득할 수 없어야 한다. 방어적 복사본을 만들어라.

변경 불가능한 객체는 그 내부도 공유할 수 있고, 다른 객체의 구성 요소로도 훌륭하다. 다만 값마다 별도로 객체를 만들어야 하므로 객체 생성 비용이 높을 수 있다.

최대한 변경 불가능한 클래스로 만들되 불가능하다면 변경 가능성을 최대한 제한하라.

 

규칙 16: 상속 대신 구성을.

메소드 호출과 달리 상속은 캡슐화 원칙을 위반한다. 부모의 변화에 영향을 받는 깨지기 쉬운 상태의 클래스가 된다.

 기존 클래스를 상속하는 대신 새로운 클래스에 기존 클래스 객체를 참조하는 private 필드를 하나 두자. 이런 설계 기법을 구성이라고 부른다. 기존 클래스가 새 클래스의 일부가 되기 때문이다. 새로운 클래스에 포함된 각각의 메소드는 기존 클래스에 있는 메소드 가운데 필요한 것을 호출해서 그 결과를 반환하면 된다. 이를 전달(forwarding)이라고 한다.

 

상속은 하위 클래스가 상위 클래스의 하위 자료형 (subtype)이 확실할 경우에만 바람직하다. 확실한 게 아니라면 안 된다.

 

규칙 17: 상속을 위한 설계와 문서를 갖추거나 그럴 수 없다면 상속을 금지해라.

재정의 가능 메소드를 내부적으로 어떻게 사용하는지 반드시 문서에 남겨라.

public이나 protected로 선언된 모든 메소드와 생성자에 대해, 어떤 재정의 가능 메소드를 어떤 순서로 호출하는지, 그리고 호출 결과가 추후 어떤 영향을 미치는지 문서로 남겨라.

상속을 허용하려면

-> 생성자, clone, readObject에서 재정의 가능 메소드를 호출해서는 안 된다.

 

규칙 18: 추상 클래스 대신 인터페이스를 사용해라.

자바는 다중 상속을 허용하지 않기 때문에 추상 클래스를 사용하면 자료형으로 사용하는데 많은 제약이 생긴다.

이미 있는 클래스를 개조해서 새로운 인터페이스를 구현하도록 하는 것은 간단하다. 또한 인터페이스는 mixin을 정의하는데 이상적이다. (mixin: primitive type 이외에 추가로 구현할 수 있는 자료형이으로, 어떤 선택적 기능을 제공한다는 사실을 선언하기 위해 쓰인다. 예를 들면 comparable이 있다. mixin인 이유는 자료형 주된 기능에 선택적 기능을 혼합할 수 있도록 하기 때문이다.)

인터페이스는 비 계층적인 자료형 프레임워크를 만들 수 있도록 한다.

인터페이스를 사용하면 wrapper class idiom(포장 클래스 숙어?)를 통해 안전하면서도 강력한 기능 개선이 가능하다. 물론 인터페이스 안에는 메소드 구현을 둘 수 없지만 그렇다고 프로그래머가 사용할 수 있는 코드를 제공할 방법이 없는 것은 아니다. abstract skeletal implmentation 클래스를 중요 인터페이스 마다 두면 인터페이스의 장점과 추상 클래스의 장점을 결합할 수 있다.

 

규칙19: 인터페이스는 자료형을 정의할 때만 사용해라.

인터페이스를 구현해 클래스를 만든다는 것은 해당 클래스의 객체로 어떤 일을 할 수 있는지 클라이언트에게 알리는 행위이다.

특정 상수를 API의 일부로 공개할 목적으로는 적절치 않다.

 

규칙20: 태그 달린 클래스 대신 클래스 계층을 활용해라.

두 가지 이상 기능을 가지고 있으며 그 중 어떤 기능을 제공하는지 표시하는 태그를 가진 클래스보단 클래스 계층을 통해 추상화하고 여러 클래스로 나눠라.

 

규칙 21: strategy pattern을 표현하고 싶다면 함수 객체를 사용해라.

 

규칙 22: Member class는 가능하면 static으로 선언해라.

Nested class는 다른 클래스 안에 정의된 클래스이다. 해당 클래스는 해당 클래스가 속한 클래스 안에서만 사용되어야 하고 그렇지 않을 경우 nested class로 만들어선 안 된다.

  • Nested class에는 4가지가 있다.
  • Nonstatic member class: member class 객체 각각이 바깥 객체에 대한 참조를 가져야 하는 경우
  • Static member class: 그렇지 않은 경우
  • Anonymous class: 오직 한곳에서만 객체를 생성하며 해당 중첩 클래스의 특성을 규정하는 경우. 선언하는 순간에만 사용될 수 있으므로 프로세스 객체를 만들거나 정적 팩터리 메서드 안에서도 많이 쓰인다.
  • Local class: 그 외의 경우

로 나뉜다.

 

바깥 클래스 객체에 접근할 필요가 없는 멤버 클래스를 정의할 때는 항상 선언문 앞에 static을 붙여서 non-static class 대신 static class로 만들자. 그렇지 않으면 GC가 까다로워진다.