짧은 코멘트와 함께하는 이펙티브 자바) #15 클래스와 멤버의 접근 권한을 최소화하라
짧은 코멘트
- 클래스와 메소드, 그리고 필드의 접근 권한을 적절히 설정하는 일은 단순히 접근할 수 있다 / 없다 뿐 아니라, 코드를 읽는 사람 입장에서, '이 필드는 밖에서도 사용되나?' / '이 코드는 내부에서만 사용되구나'를 유추할 수 있게 해주는 수단이다. 때문에 clean code에 있어 기초적이면서도 중요하다고 생각한다.
- 가끔 단위 테스트를 작성하기 위해 private method를 public method로 만드는 분들이 계시는데, 그 보다 나은 방법은 default 접근 권한을 사용하는 것이다. 그리고 그 보다 조금 더 나은 방법은 테스트 해야할 부분과 테스트를 해야하지 않을 부분을 명확히 구분하여 외부로 하여금 내부를 테스트 하게 하는 것이다. (lannstark.tistory.com/105 참고)
클래스와 멤버의 접근 권한을 최소화하라
어설프게 설계된 컴포넌트와 잘 설계된 컴포넌트의 가장 큰 차이는 바로 클래스 내부 데이터와 내부 구현 정보를 외부 컴포넌트로부터 얼마나 잘 숨겼느냐이다.
이 정보 은닉 혹은 캡슐화라고 하는 개념은 SW 설계의 근간이 되는 원리이다. 정보 은닉의 장점 중 대부분은 시스템을 구성하는 컴포넌트들을 서로 독립시켜서 개발, 테스트, 최적화, 적용, 분석, 수정을 개별적으로 할 수 있게 해주는 것과 연관되어 있다.
JAVA의 접근 제어 메커니즘은 클래스, 인터페이스, 멤버의 접근성을 명시한다. 이 접근 제한자를 제대로 활용하는 것이 정보 은닉의 핵심이다.
기본 원칙은 간단하다. 모든 클래스와 멤버의 접근성을 가능한 한 좁혀야 한다. SW가 올바로 동작하는 한 항상 가장 낮은 접근 수준을 부여해야 한다.
톱 레벨 클래스와 인터페이스에 부여할 수 있는 접근 수준은 package-private(default)과 public이다.
class PackagePrivateClass {}
패키지 외부에서 쓸 이유가 없다면 package-private으로 선언하자.
멤버에 부여할 수 있는 접근 수준은 네 가지이다.
- private : 멤버를 선언한 top level 클래스에서만 접근할 수 있다.
- package-private (default) : 멤버가 소속된 패키지 안의 모든 클래스에서 접근할 수 있다.
- protected : default의 접근 범위를 포함하며, 이 멤버를 선언한 클래스의 하위 클래스에서도 접근할 수 있다.
- public : 모든 곳에서 접근할 수 있다.
공개 API를 세심하게 설계한 후, 모든 멤버는 private으로 만들자. 그런 다음 필요한 경우에 권한을 풀어주자. 단, 권한을 풀어 주는 일을 자주 하게 된다면 컴포넌트를 더 분해해야 하는 것이 아닌지 다시 고민해보자. protected 멤버의 수는 적을 수록 좋다.
public 클래스의 인스턴스 필드는 되도록 public이 아니어야 한다. public 가변 필드를 갖는 클래스는 일반적으로 스레드 안전하지 않다.
해당 클래스가 표현하는 추상 개념을 완성하는 데 꼭 필요한 구성요소로써의 상수라면 public static final 필드를 공개해도 좋다. 이런 필드는 반드시 기본 타입이거나 불변 객체를 참조해야 한다.
클래스에서 public static final 배열 필드를 두거나 이 필드를 반환하는 접근자 메소드를 제공해서는 안된다. 길이가 0이 아닌 배열은 모두 변경할 수 있기 때문이다.
자바 9에서는 모듈 시스템이라는 개념이 도입되었다. 모듈은 자신에 속하는 패키지 중 공개(export)할 것들을 선언한다. 모듈 시스템을 활용하면 클래스를 외부에 공개하지 않으면서도 같은 모듈을 이루는 패키지 사이에서는 자유롭게 공유할 수 있다. 모듈에 적용되는 새로운 두 접근 수준은 상당히 중요해서 사용해야 한다. 여러분 모듈으 JAR 파일을 자신의 모듈 경로가 아닌 애플리케이션 클래스패스에 두면 그 모듈 안의 모든 패키지는 마치 모듈이 없는 것처럼 행동한다. 모듈 개념이 널리 받아들여질지 예측하기에는 아직 이른 감이 있다. 그러니 꼭 필요한 경우가 아니라면 당분간은 사용하지 않는게 좋을 것 같다.