Item15. 클래스와 멤버의 접근 권한을 최소화하라!
- 컴포넌트의 설계는 클래스 내부 데이터와 내부 구현 정보를 외부 컴포넌트로부터 얼마나 잘 숨겼는지로 평가한다.
- 잘 설계된 컴포넌트는 모든 내부 구현을 완벽히 숨겨, 구현과
API를 깔끔히 분리한다. - 정보 은닉, 캡슐화라고 하는 이 개념은 소프트웨어 설계의 근간이 되는 원리다.
정보 은닉의 장점
- 시스템 개발 속도를 높인다.
- 여러 컴포넌트를 병렬로 개발할 수 있기 때문
- 시스템 관리 비용을 낮춘다.
- 각 컴포넌트의 파악이 빨라져 디버깅 속도 증가하고, 다른 컴포넌트로 교체하는 비용도 작기 때문
- 정보 은닉 자체가 성능 향상을 보이진 않지만, 성능 최적화에 도움을 준다.
- 시스템 프로파일링 후 최적화 필요한 컴포넌트를 정해 다른 컴포넌트에는 영향을 주지 않고 해당 컴포넌트만 최적화할 수 있기 때문
- 소프트웨어 재사용성을 높인다.
- 외부에 거의 의존하지 않는 독자적 컴포넌트라면 낯선 환경에서도 유용하게 쓰일 수 있기 때문
- 큰 시스템 제작의 난이도를 낮춰준다.
- 시스템 전체가 완성되지 않았어도 개별 컴포넌트의 동작 확인이 가능하기 때문
접근 제어 메커니즘
- 클래스, 인스턴스, 멤버의 접근성을 명시한다.
- 각 요소의 접근성은 그 요소가 선언된 위치와 접근 제한자로 정해진다.
기본원칙
- 모든 클래스와 멤버의 접근성을 가능한 한 좁혀야 한다.
접근 수준
클래스,인터페이스
top-level클래스와 인터페이스에 부여할 수 있는 접근 수준은package-private,public두 가지다.public으로 선언 시, 공개 API가 된다.package-private로 선언 시, 해당 패키지 안에서만 이용 가능하다.- 외부에서 사용할 일 없으면
package-private으로 선언해 내부 구현으로 사용한다. 그럼 언제든 수정, 교체, 제거가 가능하다.
- 한 클래스에서만 사용하는
package-private인top-level클래스나 인터페이스는 클래스 안으로 이동시키고,private static으로 중첩시켜 사용하자.
멤버
| 같은 클래스 접근 | 같은 패키지 접근 | 상속 클래스 접근 | 외부에서 접근 | |
|---|---|---|---|---|
| public | Yes | Yes | Yes | Yes |
| protected | Yes | Yes | Yes | No |
| package-private | Yes | Yes | No | No |
| private | Yes | No | No | No |
유의 사항
클래스의
공개 API를 세심히 설계한 후, 그 외의 모든 멤버는private으로 만들자.- 그 후 오직 다른 패키지의 다른 클래스가 접근해야 하는 멤버에 한해
package-private으로 변경한다. private,package-private멤머는 모두 해당 클래스의 구현에 해당해공개 API에 영향을 주지 않는다.
- 그 후 오직 다른 패키지의 다른 클래스가 접근해야 하는 멤버에 한해
public클래스에서 멤버 수준을package-private에서protected로 바꾸는 순간 접근할 수 있는 대상이 확 늘어난다. 고려 필요하다.상위 클래스의 메서드 재정의 시, 상위 클래서 메서드보다 좁은 범위의 제한자 사용은 불가하다.(리스코프 치환 원칙) 이 경우는 멤버 접근성을 좁히지 못하는 특별한 예외이다.
코드를 테스트하는 목적으로 클래스, 인터페이스, 멤버의 접근 범위를 넓히는 경우, 적당 수준까지는 괜찮다. 하지만 이를
공개 API로 만들어서는 안된다.public클래스의 인스턴스 필드는 되도록public이 아니어야 한다.- 불변식을 보장할 수 없게 됨을 주의해야 한다.
public static final필드의 상수라면 예외적으로 공개해도 좋다.
길이가 0이 아닌 배열은 모두 변경이 가능하다. 따라서 클래스에
public static final배열 필드를 두거나 이 필드를 반환하는 접근자 메서드 제공을 해서는 안된다.1 2
// 문제 있음. 불변 보장 안됨. public static final Thing[] VALUES = {...};
public배열을private로 만들고,public불변 리스트를 추가해 해결한다.1 2 3
private static final Thing[] PRIVATE_VALUES = {...}; public static final List<Thing> VALUES = Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));
배열을
private로 만들고, 그 복사본을public메서드로 반환해 해결한다.1 2 3 4
private static final Thing[] PRIVATE_VALUES = {...}; public static final Thing[] values() { return PRIVATE_VALUES.clone(); }
핵심 정리
- 프로그램 요소의 접근성은 가능한 한 최소한으로 하자.
- 꼭 필요한 것만 최소한의
public API로 설계하자. - 클래스, 인터페이스, 멤버가 의도치 않게
API로 공개되는 일은 없어야 한다. public클래서는public static final상수 필드 외에는 어떠한public필드도 허용해서는 안된다.public static final필드가 불변인지 확인하자.
Comments powered by Disqus.