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.