본문 바로가기

책, 강의 정리/이펙티브자바

[아이템 15] 클래스와 멤버의 접근 권한을 최소화하라

잘 설계된 컴포넌트란?

1. 캡슐화가 얼마나 잘 되었는지.

2. 노출되는 API 와 실제 구현이 얼마나 잘 분리되었는지.

3. 메시지를 주고받는 두 컴포넌트가 서로의 내부 동작을 신경쓰지 않는지.

 

 

캡슐화를 잘 지켰을 때의 장점

1. 서로의 구현을 몰라도 되기 때문에 병렬로 개발이 가능하여 개발 속도가 빨라진다.

2. 잘 분리되어있는 컴포넌트는 관리포인트가 작다. 디버깅도 빨리 할 수 있고 다른 컴포넌트로의 교체도 빠르게 할 수 있다.

3. 잘 분리되어있는 컴포넌트는 최적화도 그 컴포넌트만 하면 되기 때문에 좋다.

4. 외부 컴포넌트에 종속되지 않기 때문에 재사용성이 높다.

5. 전체 시스템이 완성되지 않아도 개별 컴포넌트를 검증할 수 있기 때문에 큰 시스템을 개발하는 난이도를 낮춰준다.

 

 

 

 

캡슐화의 핵심은 "접근제어자"

기본원칙: 모든 클래스와 멤버의 접근성을 가능한 한 좁혀야 한다.

 

private: 멤버를 선언한 톱레벨 클래스에서만 접근 가능.
package-private: 멤버가 소속된 패키지 않의 모든 클래스에서 접근 가능.
protected: package-private + 하위클래스에서 접근가능
public: 모든 곳에서 접근 가능

 

 

캡슐화 방법

공개 API 를 설계하고 그것만 public 으로 지정한다 > 나머지는 private 으로 만든다 > 구현 중 같은 패키지의 다른 클래스가 접근해야하면 package-private 으로 풀어준다.

이 과정에서 너무 자주 풀어주는 일이 발생한다면 컴포넌트를 더 분해해야 하는 것일 수도 있다.

+ 추가로 고려해야 할 사항

1. 한 클래스에서만 사용하는 package-private 톱레벨 클래스나 인터페이스는 private 정적클래스로 중첩시켜본다. 이 중첩클래스는 포함된 톱레벨 클레스에서만 접근할 수 있다.

2. public 일 필요가 없는 클래스는 package-private 클래스로 바꾸자.

 

private, package-private가 공개 API가 될 수 있는 "Serializable" 구현(검토가 필요합니다... ㅎㅎ)

위와 같이 모든 멤버변수가 private 인 Member 클래스를 직렬화한 뒤,

위처럼 public 으로 변경된 Member 클래스로 역직렬화 할 수 있다.

private 었던 password 가 공개 API 가 되었다.

 

 

공개 API의 제약

공개 API는 영원히 지원되어야 한다. 또, 필요에따라 문서화되어야 한다. 그러므로 접근제어는 최대한 좁힐 수 있을 만큼 좁히자.

하지만 리스코프 원칙을 지키기 위해 하위클래스는 상위클래스보다 좁혀질 수 없다.

 

 

 

public 클래스의 인스턴스 필드가 public 이 되어서는 안되는 이유

1. 변경에 매우 취약하다.

2. 스레드 안전하지 않다.
인스턴스 변수는 힙에 할당되며 공유자원이다. 즉, 모든 스레드가 이 공유자원에 접근 할 수 있다.
public 인스턴스 변수는 Foo.resource와 같이 접근하기 때문에 다른 작업을 할 수 없다. 책의 예시처럼 Lock 획득 같은 "thread safe" 하도록 부가적인 작업을 할 수 없기 때문에 사용해서는 안된다.

3. public final 필드의 문제점.
private 필드라면 내부 구현 변경 시 private 필드를 삭제할 수 있고, Getter든 Setter든 해당 클래스 내부만 수정하면 된다. 하지만 public final 필드의 경우 내부 구현 변경 시 이 필드가 직접 사용되고 있는 모든 소스코드를 찾아가 수정해야한다.

유일하게 허용되는 public static final 필드
추상 개념을 완성하는데 꼭 필요한 "상수"
관용적으로 대문자알파벳과 _ 의 조합으로 이루어져있으며 기본타입 또는 불변객체를 참조해야한다.

public static final 필드가 가변객체를 참조한다면?

위와같이 가변객체 Subject 를 private static final 로 참조한다면, 해당 참조만 그대로 유지하고 그 값만 변경하는 식으로 "불변"을 깰 수 있다.

 

 

자바 9부터 도입된 모듈 시스템

1. 모듈은 자신이 공개할 패키지를 선언해야함. 즉, public, protected여도 공개대상이 아니면 외부에서 접근할 수 없음.

2. jar 패키징 시 module-info 를 포함하여 패키징하기 때문에 프로젝트루트의 classpath 에 추가하여도 공개하지 않은 모듈은 접근할 수 없다.