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

Jimin Lim·2022년 3월 26일
0

Effective Java

목록 보기
15/38
post-thumbnail

아이템 15

클래스와 멤버의 접근 권한을 최소화하라

잘 설계된 컴포넌트는 클래스의 내부 데이터와 내부 구현 정보를 외부 컴포넌트로부터 잘 숨긴 것이다. 이를 정보 은닉 혹은 캡슐화라고 부르며 장점은 아래와 같다.

  1. 시스템 개발 속도를 높인다.
    여러 컴포넌트를 병렬로 개발할 수 있기 때문이다.
  2. 시스템 관리 비용을 낮춘다.
    각 컴포넌트를 더 빨리 파악해 디버깅할 수 있고 다른 컴포넌트로 교체하는 부담도 적다.
  3. 성능 최적화에 도움을 준다.
    완성된 시스템을 프로파일링해 최적화할 컴포넌트를 정한 후, 다른 컴포넌트에 영향을 주지 않고 해당 컴포넌트만 최적화할 수 있기 때문이다.
  4. 소프트웨어 재사용성을 높인다.
    컴포넌트와 함께 개발되지 않은 낯선 환경에서도 유용하게 쓰일 가능성이 크다.
  5. 큰 시스템을 제작하는 난이도를 낮춰준다.
    개별 컴포넌트의 동작을 시스템 전체가 완성되지 않아도 동작을 검증할 수 있다.

자바에서는 접근 제한자와 선언된 위치로 접근성이 정해진다. 여기서 접근 제한자를 제대로 활용하는 것이 정보 은닉의 핵심이다.

접근 제한자

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

클래스, 인터페이스

가장 바깥이라는 의미의 톱레벨 클래스와 인터페이스에 부여할 수 있는 접근 수준은 package-privatepublic 두 가지다.
public: 공개 API
package-private: 해당 패키지 안에서만 이용 가능, 패키지 외부에서 쓸 이유가 없다면 선언
public일 필요가 없는 클래스의 접근 수준을 package-private 톱레벨 클래스로 좁힐 필요가 있다.

package-private를, 사용하는 클래스에 private static으로 중첩시켜보자. 톱레벨로 두면 같은 패키지의 모든 클래스가 접근할 수 있지만, private ststic으로 중첩시키면 바깥 클래스 하나에만 접근할 수 있다.

멤버

private: 멤버를 선언한 톱레벨 클래스에서만 접근 가능
package-private: 멤버가 소속된 패키지 안의 모든 클래스에서 접근 가능
protected: package-private의 접근 범위 포함, 이 멤버를 선언한 클래스의 하위 클래스에서도 접근 가능하다.
public: 모든 곳에서 접근 가능

범위 제한

  1. 클래스의 공개 API를 세심히 설계한 후, 그 외의 모든 멤버는 private으로 만들자.
  2. 다른 클래스가 접근해야 하는 멤버만 package-private으로 풀어주자.

단, serializable을 구현한 클래스에서는 그 필드들도 의도치 않게 공개 API가 될 수 있다.
public 클래스에서 멤버의 접근 수준을 package-private에서 protected로 바꾸는 순간 멤버에 접근할 수 있는 대상 범위는 매우 넓어진다. 따라서 protected 멤버의 수는 적을수록 좋으며 테스트할 시에도 package-private까지 풀어주는 것을 허용 한다.

하지만 제약이 존재하는데, 상위 클래스는 하위 클래스로 대체할 수 있다는 규칙인 리스코프 치환 원칙에 의해, 재정의하는 하위 클래스는 상위 클래스보다 범위를 좁게 설정할 수 없다.

public 클래스의 인스턴스의 필드는 public이 되면 안되는 이유

  1. 불변식을 보장할 수 없게 된다.
  2. 스레드 안전하지 않다.
    필드가 수정될 때 다른 작업을 할 수 없게 된다.

단, 상수라면 public static final 필드로 공개해도 좋다. 이런 관례의 상수는 대문자 알파벳과 '_'의 조합으로 구성된다.

길이가 0이 아닌 배열은 주의해야 한다.

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

위와 같이 작성을 한다면 외부에서 수정이 가능하다. 해결책은 아래 두 가지가 존재한다.

public 배열을 private으로 변경, public 불변 리스트 추가

private static final String[] PRIVATE_VALUES = {...};

public static final List<String> VALUES = Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));

배열을 private으로 만들고 복사본 반환하는 public 메서드 추가

private static final String[] PRIVATE_VALUES = {...};

public static final String[] values() {
  return PRIVATE_VALUES.clone();
}

자바 9

모듈 개념 추가, 패키지가 클래스의 묶음이듯 모듈은 패키지들의 묶음을 의미한다.

모듈은 자신에 속하는 패키지 중 공개할 것들을 선언하고 protected, public 멤버라도 해당 패키지를 공개하지 않았다면 모듈 외부에서는 접근할 수 없다.
jar파일을 모듈 경로가 아닌, 애플리케이션의 클래스패스에 두면 모듈이 공개했는지 여부와 상관없이 public 클래스가 선언한 모든 public, protected 멤버를 모듈 밖에서 접근할 수 있게 된다.

핵심 정리

접근성은 가능한 한 최소한으로 하라. 클래스, 인터페이스, 멤버가 의도치 않게 API로 공개되는 일이 없어야 한다. public 클래스는 상수용 public static final 필드 외에는 어떠한 public 필드도 가져서는 안 된다.

profile
💻 ☕️ 🏝 🍑 🍹 🏊‍♀️

0개의 댓글