기록이 힘이다.

[이펙티브 자바] 15. 클래스와 멤버의 접근 권한을 최소화하라. 본문

JAVA

[이펙티브 자바] 15. 클래스와 멤버의 접근 권한을 최소화하라.

dev22 2023. 3. 21. 06:53
728x90

어설프게 설계된 컴포넌트와 잘 설계된 컴포넌트의 가장 큰 차이는 바로 클래스 내부 데이터와 내부 구현 정보를 외부 컴포넌트로부터 얼마나 잘 숨겼느냐다. (정보은닉, 혹은 캡슐화)

 

정보 은닉의 장점

-시스템 개발 속도를 높인다. 

-시스템 관리 비용을 낮춘다. 

-정보 은닉 자체가 성능을 높여주지는 않지만, 성능 최적화에 도움을 준다.

-소프트웨어 재사용성을 높인다. 

-큰 시스템을 제작하는 난이도를 낮춰준다. 

 

자바는 접근 제어 메커니즘은 클래스, 인터페이스, 멤버의 접근성(접근 허용 범위)를 명시한다. 각 요소의 접근성은 그 요소가 선언된 위치와 접근 제한자(private, protected, public)로 정해진다. 이 접근 제한자를 제대로 활용하는 것이 정보 은닉의 핵심이다. 

 

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

 

public으로 선언한다면 API가 되므로 하위 호환을 위해 영원히 관리해줘야만 하낟. 

public일 필요가 없는 클래스의 접근 수준을 package-private 톱레벨 클래스로 좁히는 일이다. public 클래스는 그 패키지의 API인 반면, package-private 톱레벨 클래스는 내부 구현에 속하기 때문이다. 

 

클래스의 공개 API를 세심히 설게한 후, 그 외의 모든 멤버는 private으로 만들자. 

 

proteced 멤버의 수는 적을수록 좋다.

 

상위 클래스의 메서드를 재정의할 때는 그 접근 수준을 상위 클래스에서보다 좁게 설정할 수 없다. 리스코프 치환 원칙. 이 규칙을 어기면 하위 클래스를 컴파일할 때 오류가 난다. 

 

public 클래스의 인스턴스 필드는 되도록 public이 아니어야 한다. public 가변 필드를 갖는 클래스는 일반적으로 스레드 안전하지 않다. 심지어 필드가 final이면서 불변 객체를 참조하더라도 문제는 여전히 남는다. 내부 구현을 바꾸고 싶어도 그 public 필드를 없애는 방식으로는 리팩터링할 수 없게 된다. 

 

예외, 해당 클래스가 표현하는 추상 개념을 완성하는 데 꼭 필요한 구성요소로써의 상수라면 public static final 필드로 공개해도 좋다. 관례상 이런 상수의 이름은 대문자 알파벳으로 쓰며, 각 단어 사이에 밑줄(_)을 넣는다.

 

길이가 0이 아닌 배열은 모두 변경 가능하니 주의하자. 따라서 클래스에서 public static final 배열 필드를 두거나 이 필드를 반환하는 접근 메서드를 제공해서는 안 된다. 이런 필드나 접근자를 제공한다면 클라이언트에서 그 배열의 내용을 수정할 수 있게 된다.

 

//보안 허점이 숨어 있다. 

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에서는 모듈 시스템이라는 개념이 도입. 모듈 시스템을 활용하면 클래스를 외부에 공개하지 않으면서도 같은 모듈을 이루는 패키지 사이에서는 자유롭게 공유할 수 있다. 대표적인 예가 JDK, 아직 예측 힘들므로 당분간 사용 자제.

 

핵심정리

프로그램 요소의 접근성은 가능한 한 최소한으로 하라. public 클래스는 상수용 public static final 필드 외에는 어떠한 public 필드도 가져서는 안되며 참조 객체가 불변인지 확인하라.