item 15) 클래스와 멤버의 접근 권한을 최소화하라
정보 은닉 / 캡슐화의 필요성
클래스 내부 데이터와 내부 구현 정보를 외부 컴포넌트로부터 얼마나 잘 숨겼느냐에 따라 컴포넌트의 설계 완성도가 달라짐
API를 통해서만 다른 컴포넌트와 소통하며 서로의 내부 동작 방식에는 관여하지 않도록 분리해야 한다.
시스템을 구성하는 컴포넌트들을 서로 독립시켜 개발, 테스트, 최적화, 적용, 분석, 수정을 개별적으로 할 수 있다.
장점
시스템 개발 속도를 높인다.
여러 컴포넌트를 병렬로 개발할 수 있기 때문이다.
시스템 관리 비용을 낮춘다.
각 컴포넌트를 더 빨리 파악하고 디버깅할 수 있고, 다른 컴포넌트로 교체하는 부담도 적기 때문이다.
성능 최적화에 도움을 준다.
완성된 시스템을 프로파일링해 최적화할 컴포넌트를 정한 다음, 다른 컴포넌트에 영향을 주지 않고 해당 컴포넌트를 최적화할 수 있기 때문이다.
소프트웨어 재사용성을 높인다.
외부에 거의 의존하지 않고 독자적으로 동작할 수 있는 컴포넌트라면 그 컴포넌트와 함께 개발되지 않은 낯선 환경에서도 유용하게 쓰일 가능성이 크기 때문이다.
큰 시스템을 제작하는 난이도를 낮춘다.
시스템 전체가 아직 완성되지 않은 상태에서도 개별 컴포넌트의 동작을 검증할 수 있기 때문이다.
접근제한자
접근 제한자를 제대로 활용하는 것이 정보 은닉의 핵심이다.
모든 클래스와 멤버의 접근성을 가능한 한 좁혀야 한다.
톱레벨 클래스와 인터페이스에 부여할 수 있는 접근 수준은 package-private와 public
패키지 외부에서 쓸 이유가 없다면 package-private으로 구현해 클라이언트에 영향을 주지 않고 언제든 수정, 교체, 제거할 수 있도록 한다.
public으로 선언하면 공개 API가 되어 하위 호환을 위해 영원히 관리해주어야 한다.
public일 필요가 없는 클래스의 접근 수준을 package-private 톱레벨 클래스로 좁혀 내부 구현에 속하도록 한다.
접근 제한자의 종류
private: 멤버를 선언한 톱레벨 클래스에서만 접근할 수 있다.
package-private: 멤버가 소속된 패키지 안의 모든 클래스에서 접근할 수 있다. 접근 제한자를 명시하지 않았을 때 적용되는 패키지 접근 수준이다. (단, 인터페이스의 멤버는 기본적으로 public이 적용된다).
protected: package-private의 접근 범위를 포함하며, 이 멤버를 선언한 클래스의 하위 클래스에서도 접근할 수 있다(제약이 조금 따른다[JLS, 6.6.2]).
public: 모든 곳에서 접근할 수 있다.
접근 제한자 사용법
클래스의 공개 API를 설계 후 해당하지 않는 모든 멤버는 private으로 만든다.
같은 패키지의 다른 클래스가 접근해야 하는 멤버에 한해 private 제한자를 제거해 package-private하게 만든다.
단, Serializable 구현한 클래스에서는 필드들이 의도치 않게 공개 API가 될 수 있다.(item 86, 87)
public 클래스의 protected 멤버는 공개 API이므로 문서화하거나 영원히 지원해야 할 수 있으므로 최소화 할 것.
리스코프 치환 법칙에 의해 상위 클래스의 메서드 재정의 시 접근 수준을 상위 클래스보다 좁게 설정할 수 없다. 클래스가 인터페이스를 구현 시 구현 메서드를 public으로 정의해야 한다.
테스트 접근 범위
테스트를 위해 접근 범위를 넓힐 때에는 public 클래스의 private멤버를 package-private하게 풀어주어 테스트 코드를 테스트 대상과 같은 패키지에 두어 테스트 할 수 있도록 한다.
public 필드
public 클래스의 필드가 가변 객체를 참조하거나 final이 아닌 필드가 public일 경우 클래스가 필드의 값을 제한할 힘을 잃게 된다.
필드가 수정될 때 다른 작업을 할 수 없으므로 public 가변 필드를 갖는 클래스는 thread-safe하지 않다.
필드가 final이면서 불변 객체를 참조하더라도 내부 구현을 바꾸고 싶을 때 public 필드를 없앨 수 없다.
해당 클래스가 표현하는 추상 개념을 완성하는 데 꼭 필요한 구성요소로써의 상수라면 pubic static final 필드로 공개한다. 반드시 기본 타입 값이나 불변 객체를 참조해야 한다.
배열
길이가 0 보다 긴 배열은 모두 변경 가능하기 때문에 public static final 이나 이 필드를 반환하는 접근자 메서드를 제공하면 안됨
배열을 필드에 사용 시 1) public 배열 대신 private 배열을 두고 public 불변 리스트를 추가하거나, 2) private 배열을 두고 clone()을 반환하는 public 메서드를 추가해 구현할 수 있다.
모듈
자바 9에서 도입된 "모듈 시스템" 활용하면 클래스를 외부에 공개하지 않으면서 같은 모듈을 이루는 패키지 사이에 자유롭게 공유 가능
모듈의 JAR 파일을 자신의 모듈 경로가 아닌 애플리케이션의 클래스패스에 두면 그 모듈 안의 모든 패키지가 모듈이 없는 것 처럼 동작해 public 클래스가 선언한 모든 public/protected 멤버를 모듈 밖에서 접근 가능
JDK는 모듈을 활용하고 있으나 아직 모듈 개념이 널리 받아들여지지 않아 당분간은 사용하지 않는게 좋을 것
Last updated