<Effective Java> RULE 13 클래스와 멤버의 접근 권한은 최소화 하라
잘 설계된 모듈과 그렇지 못한 모듈을 구별 짓는 가장 중요한 속성 하나는 모듈 내부의 데이터를 비롯한 구현 세부사항을 다른 모듈에 잘 감추느냐의 여부이다.
잘 설계된 모듈은 구현 세부사항을 전부 API 뒤쪽으로 감춘다.
정보은닉
→ 의존성을 낮춰서 각자 개별적으로 개발하고 시험, 최적화할 수 있도록 하는데 기초한다.
→ 시스템 개발 속도를 높이고 각각 모듈을 병렬적으로 개발할 수 있다.
→ 유지보수의 부담을 낮추고 모듈을 각각 좀더 빨리 이해할 수 있을 뿐만 아니라 다른 모듈에 영향없이 디버깅을 할 수 있다.
→ 어떤 모듈이 성능에 문제를 일으키는지 프로파일링 하기 용이하다.
→ 소프트웨어의 재사용 가능성을 높인다.
→ 대규모 시스템 개발 과정의 위험성도 낮춘다.
자바는 정보은닉을 실현할 수 있도록 다양한 도구를 제공한다.
→ 접근제어 메커니즘 : 클래스와 인터페이스, 멤버들의 접근 권한을 규정한다.
→ 어떤 개체의 접근 권한은 해당 개체가 선언된 위치와 권한 수정자에 의해 결정된다.(public, protected,public등)
각 클래스와 멤버는 가능한 한 접근 불가능하도록 만들어야한다.
→ 소프트웨어가 동작을 보증하는 한 가장 낮은 접근권한으로 설정한다.
→ 최상위 레벨 클래스나 인터페이스는 가능한 package-private으로 선언해야 한다.
접근권한
→ private : 최상위 레벨 클래스 내부에서만 접근 가능하다.
→ package-private : 같은 패키지 내의 아무 클래스나 사용할 수 있다. 기본 접근 권한
→ protected : 선언된 클래스 및 그 하위 클래스에서만 사용할 수 있다.
→ public : 어디서도 사용이 가능하다.
private와 package-private 멤버들은 클래스의 구현 세부사항이며 공개 API의 일부가 아니지만 ,
Serializable을 구현하는 멤버라면 공개 API속으로 새어나갈(leak) 수 있다.
상위 클래스 객체를 사용할 수 있는 곳에는 하위 클래스 객체도 사용할 수 있어야 하기 때문에
상위 클래스 메서드를 재정의 할 때에는 원래 메서드의 접근 권한보다 낮은 권한을 설정할 수 없다.
따라서 특정한 인터페이스를 구현하는 클래스를 만들 때는
인터페이스에 속한 모든 메서드를 해당 클래스의 public메서드로 선언해야 한다. 인터페이스의 모든 멤버는 원래 public이기 때문이다.
객체 필드는 절대로 public으로 선언하면 안된다.
비-final 필드나 변경 가능한 객체에 대한 final 참조 필드를 public으로 선언하면 필드에 저장될 값을 제한 할 수 없되되기 때문에 그 필드에 관계된 불변식을 강제할 수 없다.
필드가 변경될 때 특정한 동작이 실행이 되도록 할 수 없으므로 다중 스레드에도 안전하지 않다.
public static final 배열 필드를 두거나 배열 필드를 반환하는 접근자를 정의하면 안된다.
길이가 0이 아닌 배열은 언제나 변경 가능가능하며
클라이언트가 배열내용을 변경할 수 있으므로 보안에 취약해 진다.
public static final Things[] VALUES = { ... }; //보안 취약성 코드
/*
1. public으로 선언된 배열을 private로 바꾸고 변경 불가능한 public 리스트를 하나 생성
*/
private static final Thing[] PRIVATE_VALUES = {...}
public static final List<Thigs> VALUES =
Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));
/*
2. 배열을 Private로 선언하고 해당 배열을 복사해서 반환하는 public메서드 추가
*/
private static final Thing[] PRIVATE_VALUES = {...}
public static final Thing[] PRIVATE_CLONE_VALUES = {
return PRIVATE_VALUES.clone();
}
결론
→ 접근 권한은 가능한 낮추어라.
→ 최소한의 public API를 설계한 다음 모든 클래스 인터페이스 멤버는 API에서 제외하라.
→ public static final필드를 제외한 어떤 필드도 public 필드로 선언하지 마라.
→ public static final 필드가 참조하는 객체는 변경 불가능 객체로 만들라.