[Effectiva Java] item15 - 클래스와 멤버의 접근 권한을 최소화하라

신민철·2023년 4월 20일
1

Effective Java

목록 보기
15/23
post-thumbnail

일반적으로 캡슐화가 잘 이루어지면 잘 설계된 컴포넌트라고 한다. 내부 구현과 공개 API를 철저히 분리한다.

내부 정보를 숨기는 것에는 장점이 많은데 다음과 같다.

  • 시스템 개발 속도를 높인다: 병렬 개발 가능

  • 시스템 관리 비용을 낮춘다: 각 컴포넌트의 디버깅이 빨라지고 컴포넌트 교체의 부담이 적어진다.

  • 성능을 높여주지는 않지만 최적화에 도움을 준다: 완성된 시스템을 프로파일링하여 최적화할 컴포넌트를 정한 다음 다른 것에는 영향을 주지 않고 최적화가 가능하다.

  • 소프트웨어의 재사용성을 높인다: 외부에 의존하지 않는 컴포넌트는 떼어서 다른 낯선 환경에서도 유용하게 쓰일 가능성이 크다.

  • 큰 시스템을 제작하는 난이도를 낮춰준다: 시스템 전체가 완성되지 않아도 컴포넌트를 검증할 수 있다.


자바는 접근 제한자로 정보를 숨긴다.

기본 원칙은 모든 클래스와 멤버의 접근성을 가능한 한 좁혀야 한다 이다.

요약하자면 가장 낮은 접근 수준을 부여하라는 뜻이다.

가장 바깥 클래스인 톱레벨 클래스나 인터페이스는 public과 package-private 접근자를 부여받을 수 있다.

패키지 외부에서 쓸 이유가 없다면 package-private으로 선언하자. 그러면 릴리즈마다 수정할 수 있을 것이다.

한 클래스에서만 사용되는 package-private 톱레벨 클래스나 인터페이스는 사용되는 클래스 내부에

private static으로 중첩시키면 사용되는 톱레벨 클래스에서만 사용이 될 수 있다.


접근자는 다음과 같이 존재한다.

  • private: 멤버를 선언한 톱레벨 클래스만 접근 가능
  • package-private(default): 멤버가 소속된 패키지 내부에서 접근 가능
  • protected: 이 멤버를 선언한 하위 클래스에서도 접근 가능
  • public: 모든 곳에서 접근 가능

일반적으로 공개되어야 하는 것을 제외하고 private으로 선언하되, 패키지 내에서 접근이 되어야 하는 것들만 package-private으로 풀어주면 된다.

이를 방해하는 조건이 하나 있는데, 상위 클래스의 메소드를 재정의할 때는 접근 수준을 그것보다 같거나 범위가 넓도록 설정해야 한다. (리스코프 치환 원칙 - item10)

테스팅을 위해 접근 범위를 private을 package-private까지는 용인되나 public은 안된다. 이렇게 할 이유도 없다.

public 클래스의 인스턴스 필드는 되도록 public이 아니어야 한다. 필드가 가변 객체를 참조하거나, final이 아닌 필드를 public으로 공개하면 값을 제한하지 못한다.

락을 얻어서 동시성을 제어해야 하는 상황이 발생할 수 있는데 public이면 불가능하다. 따라서 Thread-safe하지 않다.

final이고 불변 객체를 참조해도 문제가 생기는데, 참조하는 객체는 같지만 참조된 객체는 변할 수 있기 때문이다.

구현에 꼭 필요한 상수라면 public static final로 하되, 필드명을 대문자로 선언하자.

public static final로 선언해도 주의해야 하는 필드가 있는데 바로 배열이다. 길이가 0이 아닌 배열은 모두 mutable하기 때문이다.


따라서 2가지 방법이 존재한다.

private static final Student[] PRIVATE_VALUES = { ... };
public static final List<Student> VALUES =
	Collections.unmodifiableList(Arrays.toList(PRIVATE_VALUES));

첫번째는 private 배열로 만들고 public 불변 리스트를 만드는 것이다.

private static final Student[] PRIVATE_VALUES = { ... };
public static final Student[] values() {
	return PRIVATE_VALUES.clone();
};

두번째는 private 배열을 clone()하여 반환하는 것이다.(방어적 복사)


자바 9부터 모듈 개념이 추가되면서 두가지 암묵적 접근 수준이 추가되었다.

module-info.java 에서 공개한 패키지를 정할 수 있다.

이 방식의 주의할 점은 모듈 경로가 아닌 classpath에 두면 모듈 내 모든 패키지 내의 public 멤버들은 공개가 되버린다. 이 방식을 가장 잘 활용하는 것은 JDK이다.



핵심 정리
요소의 접근성을 항상 최소한으로 두자. public 클래스는 public static final 상수 외에는 어떤 public 필드도 가져서는 안된다. 그리고 이 필드는 불변 객체인지 꼭 확인하라.

0개의 댓글