아이템15. 클래스와 멤버의 접근 권한을 최소화하라

2021. 7. 26. 13:24책/이펙티브자바

잘 설계된 컴포넌트

  • 내부 데이터와 내부 구현 정보를 외부 컴포넌트로부터 얼마나 잘 숨겼느냐.
  • 구현과 API 를 깔끔하게 분리한다.
  • 서로의 내부 동작 방식에는 전혀 개의치 않는다.

정보 은닉의 장점

  • 정보은닉, 캡슐화 라고 하는 개념은 소프트웨어 설계의 근간이 되는 원리다.
  • 시스템 개발 속도를 높인다.
    • 여러 컴포넌트를 병렬로 개발 할 수 있기 때문이다.
  • 시스템 관리 비용을 낮춘다.
    • 각 컴포넌트를 더 빨리 파악하여 디버깅 할 수 있다.
    • 다른 컴포넌트로 교체하는 부담이 적다.
  • 성능 최적화에 도움을 준다.
    • 최적화할 컴포넌트를 정한 다음 다른 컴포넌트에 영향을 주지 않고 해당 컴포넌트만 최적화가 가능하다.
  • 소프트웨어 재사용성을 높인다.
    • 외부에 거의 의존하지 않고 독자적으로 동작할 수 있는 컴포넌트라면 낯선 환경에서도 유용하게 쓰일 가능성이 크기 때문이다.
  • 큰 시스템을 제작하는 난이도를 낮춰준다.
    • 시스템 전체가 완성되지 않은 상태에서도 개별 컴포넌트의 동작을 검증할 수 있기 때문이다.

어떻게 ?

각 요소의 접근성은 그 요소가 선언된 위치와 접근제한자로 정해진다.

이 접근제한자를 제대로 활용하는 것이 정보 은닉의 핵심이다.

모든 클래스와 멤버의 접근성을 가능한 한 좁혀야 한다.

즉, 소프트웨어가 올바로 동작하는 한 항상 가장 낮은 접근 수준을 부여해야 한다는 뜻이다.

접근제한자

  • private
  • package-private (default)
  • protected
  • public

클래스의 접근제한자

패키지 외부에서 쓸 이유가 없다면 package-private으로 선언하자.

API가 아닌 내부 구현이 되어 언제든 수정할 수 있다.

반면, public으로 선언한다면 API가 되므로 하위 호환을 위해 영원히 관리해줘야만 한다.

public 일 필요가 없는 클래스의 접근 수준을 package-private 로 좁히자.

public 클래스는 그 패키지의 API 인 반면, pakcage-private 클래스는 내부 구현에 속하기 때문이다.

멤버의 접근제한자

클래스의 공개 API를 세심히 설계한 후, 그 외의 모든 멤버는 private으로 만들자.

그 다음 오직 같은 패키지의 다른 클래스가 접근해야 하는 멤버에 한해 package-private으로 풀어주자.

권한을 풀어줄때는 충분히 고민해보자

주의사항

public 클래스의 인스턴스 필드는 되도록 public이 아니어야 한다.

필드가 가변 객체를 참조하거나 final이 아닌 인스턴스 필드를 public으로 선언하면 그 필드에 담을 수 있는 값을 제한할 힘을 잃게 된다.

public 가변 필드를 갖는 클래스는 일반적으로 스레드 안전하지 않다.

해당 클래스가 표현하는 추상 개념을 완성하는데 꼭 필요한 구성요소로써의 상수라면 public static final 필드로 공개해도 좋다. 관례상 이런 상수의 변수명은 KING_SUBIN 이런식으로 대문자 알파벳과 언더스코어를 섞어 사용한다.

배열 주의사항

길이가 0이 아닌 배열은 모두 변경가능하니 주의하자.

클래스에서 public static final 배열 필드를 두거나 이 필드를 반환하는 접근자 메서드를 제공해서는 안된다.

이런 필드나 접근자를 제공하면 클라이언트에서 배열의 내용을 수정할 수 있게 된다.

// 허점
public static final Thing[] VALUES = { ... };

// 해결 1
private static final Thing[] PRIVATE_VALUES = { ... };
public static final List<Thing> VALUES = 
    Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));

// 해결 2
private static final Thing[] PRIVATE_VALUES = { ... };
public static final Thing[] values() {
    return PRIVATE_VALUES.clone();
}
  1. private 으로 만들고 public 불변 리스트 추가하기
  2. private 으로 만들고 그 복사본을 반환하는 public 메소드 추가하기 (방어적 복사)

결론

  • 프로그램 요소의 접근성은 가능한 최소한으로 하라.
  • 꼭 필요한 것만 골라 최소한의 public API로 설계하자.
  • public 클래스는 상수용 public static final 필드 외에는 어떠한 public 필드도 가져서는 안된다.
  • public static final 필드가 참조하는 객체가 불변인지 확인하라.