정보 은닉
: 잘 설계된 컴포넌트는 모든 내부 구현을 완벽히 숨겨, 구현과 API를 깔끔히 분리한 것
정보 은닉의 장점
- 여러 컴포넌트를 병렬로 개발해 시스템 개발 속도를 높임
- 시스템 관리 비용을 낮춤 (각 컴포넌트를 더 빨리 파악하여 디버깅할 수 있고, 다른 컴포넌트로 교체하는 부담도 적기 때문)
- 정보 은닉 자체가 성능을 높여주지는 않지만, 성능 최적화에 도움을 줌
- 소프트웨어 재사용성을 높임 (외부에 거의 의존하지 않고 독자적으로 동작할 수 있는 컴포넌트라면, 그 컴포넌트와 함께 개발되지 않은 낯선 환경에서도 유용하게 쓰일 가능성이 크기 때문)
- 큰 시스템을 제작하는 난이도를 낮춰줌 (시스템 전체가 아직 완성되지 않은 상태에서도 개별 컴포넌트의 동작을 검증할 수 있기 때문)
클래스, 인터페이스, 멤버의 접근성(접근 허용 범위)은 그 요소가 선언된 위치와 접근 제어자(private, protected, public)로 정해짐
모든 클래스와 멤버의 접근성을 가능한 한 좁혀야 한다!
접근 제어자
- private: 멤버를 선언한 톱레벨 클래스에서만 접근 가능
- package-private: 멤버가 소속된 패키지 안의 모든 클래스에서 접근 가능 (deflaut 접근 제어자 - 인터페이스의 멤버는 기본적으로 public 적용)
- protected: package-private의 접근 범위를 포함하며, 이 멤버를 선언한 클래스의 하위 클래스에서도 접근 가능
- public: 모든 곳에서 접근 가능
같은 클래스 | 같은 패키지 | 같은 패키지의 상속 클래스 |
다른 패키지의 상속 클래스 |
전체 클래스 | |
public | O | O | O | O | O |
protected | O | O | O | O | |
package-private | O | O | O | ||
private | O |
1. 클래스의 공개 API를 설계한 후, 그 외의 모든 멤버는 private으로 생성
2. 같은 패키지의 다른 클래스가 접근해야 하는 멤버에 한하여 package-private으로 변경
→ 권한을 풀어주는 일을 자주 하게 된다면 시스템에서 컴포넌트를 더 분해해야 하는 것은 아닌지 다시 고민할 필요有
✖️ public 클래스에서는 멤버 접근 수준을 package-private에서 protected로 바꾸는 순간 그 멤버에 접근할 수 있는 대상 범위가 넓어지므로, protected 멤버의 수는 적을수록 좋음
위처럼 먼저 접근 범위를 좁힌 후 서서히 풀어나아가야 하지만,
접근 수준을 상위 클래스에서보다 좁게 설정할 수 없기 때문에 LIS를 주의해 클래스를 설계해야 함!
LIS(리스코프 치환 원칙): 상위 클래스의 인스턴스는 하위 클래스의 인스턴스로 대체해 사용할 수 있어야 한다는 규칙
public 클래스의 인스턴스 필드는 되도록 public이 아니어야 함
- 필드와 관련된 모든 것은 불변식을 보장할 수 없게 됨
- public 가변 필드를 갖는 클래스는 일반적으로 스레드 안전하지 않음
- 내부 구현 변경을 원할 때 public 필드를 없애는 방식으로 리팩토링할 수 없음
예외: 해당 클래스가 표현하는 추상 개념을 완성하는 데 꼭 필요한 구성요소로써의 상수 (불변 객체를 참조하는 public static final 필드)
길이가 0이 아닌 배열은 모두 변경 가능하니 주의해야 함
클래스에서 public static final 배열 필드를 두거나 이 필드를 반환하는 메서드를 제공해서는 안 됨
// 보안 허점이 숨어 있다.
public static final Thing[] VALUES = {...};
첫 번째 방법
: private 배열로 변경 + public 불변 리스트 추가
private static final Thing[] PRIVATE_VALUES = { ... };
public static final List<Thing> VALUES =
Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));
두 번째 방법
: private 배열로 변경 + 복사본 반환하는 public 메서드 추가
private static final Thing[] PRIVATE_VALUES = { ... };
public static final Thing[] values() {
return PRIVATE_VALUES.clone();
}
모듈 시스템의 두 가지 암묵적 접근 수준
: 각각 public 수준과 protected 수준과 같으나, 그 효과가 모듈 내부로 한정되는 변종인 것
- 모듈은 자신에 속하는 패키지 중 공개(export)할 것들을 선언
- protected 혹은 public 멤버라도 해당 패키지를 공개하지 않았다면 모듈 외부에서 접근 불가
프로그램 요소의 접근성은 가능한 한 최소한으로 하자. 꼭 필요한 것만 골라 최소한의 public API를 설계하자.
public 클래스는 상수용 public static final 필드 외에는 어떠한 public 필드도 가져서는 안된다.
'Effective Java' 카테고리의 다른 글
[Effective Java] 아이템 17 - 변경 가능성을 최소화하라 (0) | 2022.02.02 |
---|---|
[Effective Java] 아이템16 - public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라 (0) | 2022.01.25 |
[Effective Java] 아이템14 - Comparable을 구현할 지 고려하라 (0) | 2022.01.25 |
[Effective Java] 아이템13 - clone 재정의는 주의해서 진행하라 (0) | 2022.01.25 |
[Effective Java] 아이템 12 - toString을 항상 재정의 하라 (0) | 2022.01.20 |