-
item 15 클래스와 멤버의 접근 권한을 최소화하라책/이펙티브 자바 2022. 3. 1. 22:34
ITEM 15 클래스와 멤버의 접근 권한을 최소화하라
잘 설계된 컴포넌트는 내부 데이터와 구현 정보를 외부 컴포넌트로부터 얼마나 잘 숨겼느냐로 판단 가능하다
오직 api를 통해서만 다른 컴포넌트와 소통하며 서로의 내부 동작 방식에는 전혀 개의치 않는다
정보은닉의 장점
- 시스템 개발 속도를 높인다
- 여러 컴포넌트를 병렬로 개발할 수 있기 때문
- 시스템 관리 비용을 낮춘다
- 각 컴포넌트를 더 빨리 파악하여 디버깅할 수 있고, 다른 컴포넌트로 교체하는 부담도 적기 때문
- 정보 은닉 자체가 성능을 높여주지는 않지만, 성능 최적화에 도움을 준다
- 완성된 시스템을 프로파일링해 최적화할 컴포넌트를 정한 다음, 다른 컴포넌트에 영향을 주지 않고 해당 컴포넌트만 최적화할 수 있기 때문
- 소프트웨어 재사용성을 높인다
- 외부에 거의 의존하지 않고 독자적으로 동작할 수 있는 컴포넌트라면 그 컴포넌트와 함께 개발되지 않은 낯선 환경에서도 유용하게 쓰일 가능성이 크기 때문
- 큰 시스템을 제작하는 난이도를 낮춰준다
- 시스템 전체가 아직 완성되지 않은 상태에서도 개별 컴포넌트의 동작을 검증할 수 있기 때문
자바는 정보 은닉을 위해 다양한 장치를 제공하는데 그중 접근 제어 매커니즘은 클래스, 인터페이스, 멤버의 접근성을 명시한다
각 요소의 접근성은 그 요소가 선언된 위치와 접근 제한자로 정해진다(이 접근 제한자를 잘 활용하는게 정보 은닉의 핵심이다)
기본 원칙은 모든 클래스와 멤버의 접근성을 가능한 한 좁혀야 한다
톱레벨 클래스나 인터페이스에 부여할 수 있는 접근 수준은 package-private와 public 두 가지 이다
- 톱레벨 클래스나 인터페이스를 public으로 선언하면 공개 api가 된다
- package-private로 선언하면 해당 패키지 안에서만 이용 가능하다
- 패키지 외부에서 쓸 이유가 없다면 package-private로 선언하자
- public으로 선언시 api가 되므로 계속해서 관리를 해줘야 한다
한 클래스에서만 사용하는 package-private 톱레벨 클래스나 인터페이스는 이를 사용하는 클래스 안에 private static으로 중첩 시켜보자
- private static으로 중첩 시키면 바깥 클래스 하나에서만 접근 가능
- 톱레벨로 두면 같은 패키지의 모든 클래스가 접근 가능
public일 필요가 없는 클래스의 접근 수준을 package-private 톱레벨 클래스로 좁히자
- public 클래스는 그 패키지의 api인 반면, package-private 톱레벨 클래스는 내부 구현에 속한다
public 클래스의 인스턴스 필드는 되도록 public이 아니어야 한다
- 필드가 가변 객체를 참조하거나 final이 아닌 인스턴스 필드를 public으로 선언하면 그 필드에 담을 수 있는 값을 제한할 힘이 없어진다
- 해당 필드와 관련된 모든 것은 불변식을 보장할 수 없게 된다
- 필드가 수정될 때 다른 작업을 할 수 없게 되므로 일반적으로 스레드에 안전하지 않다
- 필드가 final이면서 불변객체를 참조하더라도 문제는 남는다
- 내부 구현을 바꾸고 싶은 경우 해당 public 필드를 없애는 방식으로는 리팩토링이 안된다
- 정적 필드도 마찬가지다
- 단 해당 클래스가 표현하는 추상 개념을 완성하는 데 꼭 필요한 구성요소로써의 상수라면 public static final 필드로 공개해도 좋다
- 관례상 이런 상수는 대문자 알파벳으로 쓰며 각 단어 사이에 밑줄을 넣는다
- 이런 필드는 반드시 기본 타입값이나 불변 객체를 참조해야 한다
- 가변객체 참조시 final이 아닌 필드에 적용되는 모든 불이익이 그대로 적용된다
- 다른 객체를 참조하지 못하지만 참조된 객체 자체는 수정 가능해서 오류 발생 가능
- 가변객체 참조시 final이 아닌 필드에 적용되는 모든 불이익이 그대로 적용된다
- 길이가 0이 아닌 배열은 모두 변경 가능하니 주의하자
- 클래스에서 public static final 배열 필드를 두거나 이 필드를 반환하는 접근자 메서드를 제공해서는 안된다
- 필드가 가변 객체를 참조하거나 final이 아닌 인스턴스 필드를 public으로 선언하면 그 필드에 담을 수 있는 값을 제한할 힘이 없어진다
// 보안 허점이 있는 코드 public static final Thing[] VALUES = {....};
위와 같은 코드의 해결책
// public 배열을 private로 변경 후 public 불변 리스트를 추가 private static final Thing[] PRIVATE_VALUES = {....}; public static final List<Thing> VALUES = Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));
// 배열을 private로 만들고 그 복사본을 반환하는 public 메서드를 추가(방어적 복사) private static final Thing[] PRIVATE_VALUES = {....}; public static final Thing[] values() { return PRIVATE_VALUES.clone(); }
클라이언트가 무엇을 원하느냐를 생각해 두가지 방법중 하나를 선택하면 된다
어느 반환 타입이 더 쓰기 편한가, 성능은 무엇이 나은가를 생각해서 결정하자
- 자바 9에서는 모듈 시스템이라는 개념이 도입되어 두가지 암묵적 접근 수준이 추가되었다
- 모듈은 여러 방면에서 자바 프로그래밍시 영향을 준다
- 꼭 필요한 경우가 아니면 주의하여 사용 여부를 생각해보자
멤버에 부여할 수 있는 접근수준은 네가지이다
멤버 (필드, 메서드, 중첩 클래스, 중첩 인터페이스)
- private
- 멤버를 선언한 톱레벨 클래스에서만 접근 가능
- package-private
- 멤버가 소속된 패키지 안의 모든 클래스에서 접근 가능
- 접근 제한자를 명시하지 않으면 적용되는 패키지 접근 수준이다
- 단. 인터페이스의 멤버는 기본적으로 public
- protected
- package-private의 접근 범위를 포함
- 이 멤버를 선언한 클래스의 하위 클래스에서도 접근가능
- public
- 모든곳에서 접근가능
정리
프로그램 요소의 접근성은 가능한 한 최소한으로 하자
꼭 필요한 것만 골라서 최소한의 public api를 설계하자
의도치 않게 api로 공개되는 클래스, 인터페이스, 멤버가 없어야 한다
public 클래스는 상수용 public static final 필드 외에는 어떠한 public 필드도 가져서는 안된다
public static final 필드가 참조하는 객체가 불변인지 확인하자'책 > 이펙티브 자바' 카테고리의 다른 글
item 17 변경 가능성을 최소화하라 (0) 2022.03.03 item 16 public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라 (0) 2022.03.02 item 14 Comparable을 구현할지 고려하라 (0) 2022.02.28 item 13 clone 재정의는 주의하여 진행하라 (0) 2022.02.25 item 12 toString을 항상 재정의하라 (0) 2022.02.24 - 시스템 개발 속도를 높인다