스터디/이펙티브 자바

[Effective Java] Item15. 클래스와 멤버의 접근 권한을 최소화

📝 작성 : 2022.05.29  ⏱ 수정 : 
728x90

캡슐화의 장점

  1. 개발속도 향상: 여러 컴포넌트를 병렬로 개발할 수 있기 때문
  2. 시스템 관리비용 감소: 빠른 파악 및 적은 교체 부담
  3. 성능 최적화에 도움: 캡슐화 자체가 성능을 높여주지는 않지만, 다른 컴포넌트에 영향을 주지 않고 특정 컴포넌트만 최적화 가능
  4. 재사용성 향상: 외부에 거의 의존하지 않고 독자적으로 동작한다면 다른 환경에서도 유용하게 쓰일 가능성이 높음
  5. 큰 시스템 제작 난이도 감소: 시스템이 완성되지 않은 상태에도 개별 컴포넌트의 동작을 검증할 수 있음

접근 제어 메커니즘

정보 은닉(캡슐화)를 위한 다양한 장치 중 하나. 접근 제어자(private, default(package-private), protected, public)로 각 요소의 접근성을 결정

접근 제어자 적용 가능 대상 같은 클래스 같은 패키지 하위 클래스(다른 패키지의 하위클래스까지) 그 외
private 생성자, 메서드, 필드 O X X X
default 클래스, 생성자, 메서드, 필드 O O X X
protected 생성자, 메서드, 필드 O O O X
public 클래스, 생성자, 메서드, 필드 O O O O

접근 제어를 통한 정보 은닉

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

클래스 수준

클래스와 인터페이스에 부여할 수 있는 접근 제어자는 default(package-private), public 입니다. public으로 선언하면 공개 API란 의미로 받아들일 수 있으므로 굳이 패키지 외부에서 사용할 이유가 없다면 default로 선언해줍니다. 그럼 패키지 내부에서만 사용한다는 것이 확실하므로 언제든 수정할 수 있습니다.

또한, 한 클래스에서만 사용하는 클래스나 인터페이스는 private static으로 중첩시키는 것도 좋습니다.

멤버 수준

멤버(필드, 메서드, 중첩 클래스, 중첩 인터페이스)에 부여할 수 있는 접근 제어자는 private, default, protected, public 입니다.
멤버는 기본적으로 private으로 만들고 필요하면(같은 패키지의 다른 클래스에서 사용) default로 풀어주는 형식이 좋습니다. 두 접근 제어자의 멤버는 해당 클래스의 구현에 해당하므로 보통은 공개 API에 영향을 주지 않습니다.(Serializable을 구현한 클래스에서는 공개 API가 될 수도 있습니다)

public 클래스에서 protected이상의 접근제어자는 공개 API이므로 영원히 관리해야합니다. 특히 인스턴스 필드는 public이 아니어야 합니다. 이는 객체의 불변식을 보장할 수 없게 만들기 때문입니다. 또한, 필드가 수정될 때 다른 작업을 할 수 없게 되므로 일반적으로 스레드에 안전하지 않습니다.
final이면서 불변객체를 참조한다고 괜찮다는 것은 아닙니다. 해당 필드를 제거하는 리펙토링을 하고 싶어도 할 수 없기 때문입니다.

단 하나의 예외가 있다면 해당 클래스가 표현하는 추상 개념을 완성하는데 꼭 필요한 상수라면 public static final 필드로 공개해도 좋습니다. 관례상 이런 경우 대문자 스네이크 케이스로 작성합니다. 이런 필드는 반드시 기본 타입이나 불변 객체를 참조해야 합니다.

길이가 0이 아닌 배열은 변경이 가능하니 이러한 필드를 제공하거나 반환하는 메서드를 제공해서는 안됩니다. 이런 경우 해당 필드를 private으로 제한하고 불변 리스트를 반환하거나 복사본을 반환하는 방법을 사용할 수 있습니다.

private static final String[] PRIVATE_VALUES = {"1", "2", "3"};

public static final List<String> VALUES = 
    Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES)); //List.of(PRIVATE_VALUES); jdk9이상

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

새로 추가된 접근 수준?

자바9에서 모듈 시스템이 도입되면서 두 가지 암묵적 접근 수준이 추가되었습니다. 모듈은 패키지들의 묶음이며 패키지 중 공개(export)할 것들을 선언(관례상 module-info.java)합니다. protected 또는 public 멤버라도 해당 패키지를 공개하지 않았다면 모듈 외부에서 접근할 수 없습니다. (물론, 모듈 안에서는 공개여부와는 상관없습니다.)
즉, 추가된 두가지 암묵적 접근 수준은 protected이지만 모듈 외부에는 비공개인, public이지만 모듈 외부에는 비공개인 수준입니다.
이 두 수준은 사용시 주의해야 하는데 모듈의 jar파일을 자신의 모듈 경로가 아닌 애플리케이션의 클래스패스에 두면 모듈이 없는 것처럼 행동합니다. 모듈 개념은 아직 익숙하지 않으므로 사용하지 않는 것이 좋겠습니다.

반응형