본문 바로가기
Effective Java

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

by byeongoo 2021. 2. 17.

어설프게 설계된 컴포넌트와 잘 설계된 컴포넌트의 가장 큰 차이는 바로 클래스 내부 데이터와 내부 구현 정보를 외부 컴포넌트로부터 얼마나 잘 숨겼느냐다. API를 통해서만 다른 컴포넌트와 소통하고 서로의 내부 동작 방식에는 전혀 개의치 않는다. 이것을 정보은닉, 혹은 캡슐화라고 한다.

 

■ 정보 은닉의 장점

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

 

■ 정보 은닉 핵심

정보 은닉의 핵심은 접근 제한자를 제대로 활용하는 것이다. 모든 클래스와 멤버의 접근성을 가능한 한 좁혀야 한다. public으로 선언하면 공개 API가 되며, package-private으로 선언하면 해당 패키지 안에서만 이용할 수 있다. public으로 선언하면 하위 호환을 위해 영원히 관리해줘야만 한다. 

 

클래스의 공개 API를 세심하게 설계한 후 그 외의 모든 멤버는 private로 만들자. 그리고 오직 같은 패키지의 다른 클래스가 접근해야하는 멤버에 한하여 package-private로 풀어주자. 권한을 풀어주는 일을 자주한다면 여러분의 시스템에서 컴포넌트를 더 분해해야 하는 것은 아닌지 다시 고민해보자.

 

■ 정보 은닉 구현 시 제약

  • 상위 클래스의 메서드를 재정의할 때는 그 접근 수준을 상위 클래스에서보다 좁게 설정할 수 없다. (리스코프 치환 원칙) 이 규칙을 어기면 하위 클래스를 컴파일할 때 오류가난다. 이때 클래스는 인터페이스가 정의한 모든 메서드를 public으로 선언해야 한다.
  • 코드를 테스트하기 위해서 클래스, 인터페이스, 멤버의 접근 범위를 넓히려 할 때가 있다. 적당한 수준까지는 넓혀도 괜찮다. 예를 들어 public 클래스의 private 멤버를 package-private까지 풀어주는 것은 허용할 수 있지만 그 이상은 안된다. 즉, 테스트만을 위해 클래스, 인터페이스, 멤버를 공개 API로 만들어서는 안된다.
  • public 클래스의 인스턴스 필드는 되도록 public이 아니어야 한다. final이 아닌 인스턴스 필드를 public으로 선언하면 불변식을 보장할 수 없다. 또한 필드가 수정될 때 (락 획득 같은) 다른 작업을 할 수 없게 되므로 public 가변 필드를 갖는 클래스는 일반적으로 스레드 안전하지 않다.