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

4장에서는 자바의 심장인 클래스인터페이스에 대해 깊게 알아본다.

정보은닉, 캡슐화

클래스 내부 데이터와 내부 구현 정보를 외부 컴포넌트로부터 잘 숨겨야 잘 설계된 컴포넌트로 볼 수 있다.

즉, 내부 구현을 완벽히 숨겨서 오로지 API를 통해서만 다른 컴포넌트와 소통하며 서로의 내부 동작 방식을 신경 쓰지 않아도 되게 만드는 것이다.

접근 제어 메커니즘

private, protected, public 과 같은 접근 제한자로 클래스, 인터페이스, 멤버의 접근성을 명시한다.

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

접근제한자 설명
private 멤버를 선언한 클래스에서만 접근할 수 있음
package-private 멤버가 소속된 패키디 안의 모든 클래스에서 접근할 수 있음
protected package-private의 접근 범위를 포함하며, 이 멤버를 선언한 클래스의 하위 클래스에서도 접근할 수 있다.
public 모든 곳에서 접근할 수 있다.

1. 톱레벨 클래스 - public 또는 package-private 결정

외부로 API로서 제공해야 하는 클래스는 public으로, 외부에서 쓰이지 않고, 해당 package 내부에서만 사용된다면 package-private으로 선언하자.

package-private 으로 선언하려면 class에 아무런 접근제어자를 명시하지 않으면 된다. (인터페이스의 멤버인 경우 기본적으로 public이 적용된다.)

class Top {
  public void print() {
  	System.out.print("Top!");
  }
}

만약, 하나의 클래스에서만 사용하는 클래스가 있다면, 이 클래스를 private static으로 중첩시켜서 사용하자.

class A {
  private static class useThisOnlyInA {
    ...
  }
}

2. public 을 결정했다면 그 외 모든 멤버는 private으로 만들자.

말 그대로, 클래스의 공개 API를 세심히 설계한 후, 그 외의 모든 멤버는 private으로 만들자. 그런 다음 오직 같은 패키지의 다른 클래스가 접근해야 하는 멤버에 한하여 package-private으로 풀어주자

Serializable을 구현한 클래스에서는 private 또는 package-private 필드들도 의도치 않게 공개 API가 될 수도 있다.

3. 멤버 변수의 접근제어

  • private : 가능한 모든 멤버 변수를 private으로 설정하자.
  • protected : 멤버를 protected로 공개하는 순간, 공개 API로 보고 영원히 해당 권한으로 지원해야 한다.
  • public : public 클래스의 인스턴스 필드는 되도록 public이 아니어야 한다.
    • 필드가 가변 객체(ex.. ArrayList)를 참조하거나, final이 아닌 인스턴스 필드를 public으로 선언하면 그 필드에 담을 수 있는 값을 제한할 힘을 잃게된다. 왜냐하면 외부에서 해당 값을 수정할 수 있기 때문이다.
    • 하지만 상수 개념이라면 public static final 필드로 공개해도 좋다.
    • private static final COLLECTION_NAME = "item_base";
      
    • 배열은 절대 안된다. 아래와 같은 코드는 외부에서 수정이 가능하다.
    • public static final Thing[] VALUES = { ... };
      

배열을 상수로 제공하고 싶을 때

  • Collections.unmodifiableList 를 사용
private static final String[] PRIVATE_VALUES = {"I", "HAVE", "PEN"};

public static final List<String> VALUES = Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));
  • clone (방어적 복사)로 리턴
public static final String[] values() {
  return PRIVATE_VALUES.clone();
}

java9에서 새로 도입된 접근자 - 모듈

패키지가 클래스들의 묶음이듯, 모듈은 패키지들의 묶음이다. 모듈은 자신에 속하는 패키지 중 export할 것들을 선언한다.

JDK 자체가 이 모듈을 활용한 예다. 자바 라이브러리에서 공개하지 않은 패키지들은 해당 모듈 밖에서는 절대로 접근할 수 없다.

댓글남기기