15. 클래스와 멤버의 접근 권한을 최소화하라
#
잘 설계된 컴포넌트의 특징정보 은닉 혹은 캡슐화
클래스 내부 데이터/구현을 완벽히 숨긴다
모든 클래스의 멤버의 가장 낮은 접근 수준 부여
→ 구현과 API 의 분리오직 API 를 통해서만 다른컴포넌트와 소통하며 서로의 내부 동작 방식에는 신경쓰지 않음
#
정보 은닉의 장점시스템을 구성하는 컴포넌트들을 서로 독립시켜서
- 개발, 테스트, 최적화, 적용, 분석, 수정을 개별적으로 할 수 있게 해준다.
- 시스템 개발속도 향상
- 여러 컴포넌트를 병렬개발
- 시스템 관리비용 절감
- 각 컴포넌트를 더 빨리 파악하여 디버깅 할수 있음
- 다른 컴포넌트로 교체비용이 더 적다
- 성능 최적화에 도움
- 다른 컴포넌트에 영향을 주지 않고 해당 컴포넌트만 최적화 할 수 있기 때문
- 소프트웨어 재사용성
- 외부에 의존하지 않고, 독자적으로 동작하는 컴포넌트는 낯선 환경에서도 유용하게 쓰임
- 큰 시스템을 제작하는 난이도를 낮춤
- 시스템 전체가 완성되지 않아도 개별 컴포넌트 동작을 검증할 수 있기 때문
#
자바가 제공하는 정보 은닉의 장치접근제어 매커니즘
- 클래스, 인터페이스, 멤버의 접근성을 명시
- 접근성 결정 요소
- 요소가 선언된 위치
- 접근 제한자 (private, protected, public)
- 정보 은닉 핵심
#
topLevel 클래스, 인터페이스tip
public 일 필요가 없는 클래스의 접근 수준을 package-private 톱 레벨 클래스로 좁히자
#
package-private해당 패키지 안에서만 이용가능
- API 가 아닌 내부 구현이 되어 언제든 수정 가능
- topLevel 클래스인 이유
- 클래스 안에 private static 으로 중첩시키면, 바깥 클래스에서 접근할 수 있게 된다.
tip
한 클래스에서만 사용하는 package-private 톱레벨 클래스나 인터페이스는 이를 사용하는 클래스 안에 private static 으로 중첩시키자
#
public- 공개 API
- 하위 호환을 위해 영원히 관리 해야 함.
#
멤버 접근 수준멤버
- 필드, 메서드, 중첩클래스, 중첩인터페이스
해당 클래스 안에서 접근 가능? | 같은 패키지 안에서 접근 가능? | 상속받은 클래스에서 접근 가능? | 외부에서 접근 가능? | |
---|---|---|---|---|
public | O | O | O | O |
protected | O | O | O | X |
package-private | O | O | X | X |
private | O | X | X | X |
#
private멤버를 선언한 톱 레벨 클래스에서만 접근 가능
#
package-private멤버가 소속된 패키지 안의 모든 클래스에서 접근 가능
- 접근 제한자를 명시하지 않았을 때 default 접근 수준
- 단 인터페이스의 멤버는 public 이 default 임
#
protectedpackage-private 의 접근 범위를 포함하며, 이 멤버를 선언한 클래스의 하위클래스에서 접근 가능
#
public모든 곳에서 접근 가능
caution
- 클래스의 공개 API 를 세심히 설계한다
- 그 외 모든 멤버는 private 으로 만든다
- 같은 패키지의 다른클래스가 접근해야 하는 멤버에 한하여 package-private 을 쓴다.
- 권한을 풀어주는 일을 자주 하게 된다면 컴포넌트를 더 분해해야 하는 것은 아닌지 다시 고민한다
#
private / package-private 멤버- 모두 해당 클래스의 구현에 해당하므로 보통은 API 에 영향을 주지 않는다.
- Serializable 을 구현한 클래스에서는 의도치 않게 공개 API 가 될 수 있다.
#
public 클래스의 protected- 공개 API, 영원히 지원되야 한다.
- 내부 동작 방식을 API 문서에 적어 사용자에게 공개해야 한다.19
- 적을수록 좋다.
#
멤버 접근성을 최소화를 방해하는 제약상위 클래스의 메서드를 재정의 할 때, 접근수준을 더 좁게 할 수 없다.
리스코프치환원칙
상위 클래스의 인스턴스는 하위 클래스의 인스턴스로 대체해 사용할 수 있어야 한다
#
테스트 목적의 접근 범위적당한 수준까지는 넓혀도 괜찮다
- public 클래스의 멤버 private → package-private 까지만 허용
- 테스트 코드를 테스트 대상과 같은 패키지에 두면 package-private 요소에 접근 가능
caution
테스트만을 위해 클래스, 인터페이스, 멤버를 공개 API 로 만들어서는 안된다.
16#
public 클래스의 인스턴스 필드는 되도록 public 이 아니어야 한다.다음과 같은 조건에, 불변식을 보장할 수 없다. (Thread safe 하지 않다)
- 필드가 가변 객체를 참조할 때
- final 이 아닌 인스턴스 필드를 public 으로 선언할 때
#
길이가 0 이 아닌 배열은 모두 변경 가능함클래스에서 public static final 배열필드를 두거나, 이 필드를 반환하는 접근자 메서드를 제공해서는 안된다.
해결책 : 클라이언트가 원하는 방향으로 둘 중 하나를 사용한다.
- 배열을 private 으로 만든다 → public 불변 리스트를 추가 한다.
- 배열을 private 으로 만든다 → 복사본을 반환하는 public 메서드를 추가한다 (방어적 복사)
#
자바9 모듈 시스템 도입패키지들의 묶음
note
- 패키지 중 export (공개) 할 것들을 (관례상 module-info.java 파일에) 선언함.
- protected / public 멤버라도 export 하지 않으면 모듈 외부에서는 접근 불가
- 클래스를 외부에 공개하지 않으면서도 같은 모듈을 이루는 패키지 사이에서는 자유롭게 공개 가능
- 모듈안의 public 클래스의 public/protected 형태로 사용하는 것은 흔치는 않다.
- 패키지들 사이에서 클래스의 재배치로 해결가능하다
#
모듈의 접근 수준은 주의해서 사용해야 함모듈의 JAR 파일을 자신의 모듈경로가 아닌 애플리케이션의 classpath 에 두면 ?? 그 모듈 안의 모든 패키지는 마치 모듈이 없는 것처럼 행동함.
- 모듈의 export 여부와 상관없이, public 클래스가 선언한 모든 public 혹은 protected 멤버를 모듈 밖에서도 접근 가능하게 된다.
#
모듈의 장점을 사용하기 위해 할 일- 패키지를 모듈 단위로 묶는다
- 모듈 선언에 패키지들의 모든 의존성을 명시한다
- 소스 트리를 재배치 한다
- 모듈 안으로 부터 일반 패키지로의 모든 접근에 특별한 조치를 해야 한다.
#
JDK 는 모듈의 접근 수준을 적극적으로 활용한 대표적인 예- 자바 라이브러리에서 공개하지 않은 패키지들은 해당 모듈 밖에서 절대로 접근 할 수 없다.
그러나 JDK 외에도 모듈 개념이 널리 받아들여질지 예측하기는 아직 이르다. 꼭 필요한 경우가 아니라면 당분간은 사용하지 않는 것이 좋다.