백엔드 개발자 블로그

[Effective Java] Item15. 클래스와 멤버의 접근 권한을 최소화하라 본문

Java

[Effective Java] Item15. 클래스와 멤버의 접근 권한을 최소화하라

backend-dev 2024. 4. 8. 22:36
어설프게 설계된 컴포넌트와 잘 설계된 컴포넌트의 가장 큰 차이는 바로 클래스 내부 데이터와 내부 구현 정보를 외부 컴포넌트로부터 얼마나 정보은닉을 잘했느냐입니다.

 

정보은닉의 장점

  • 시스템 개발 속도를 높인다. 여러 컴포넌트를 병렬로 개발할 수 있기 때문이다.
  • 시스템 관리 비용을 낮춘다. 각 컴포넌트를 더 빨리 파악하여 디버깅할 수 있고, 다른 컴포넌트로 교체하는 부담도 적기 때문이다.
  •  
  • 정보 은닉 자체가 성능을 높여 주지는 않지만, 성능 최적화에 도움을 준다.

  • 소프트웨어 재사용성을 높인다. 외부에 거의 의존하지 않고 독자적으로 동작할 수 있는 컴포넌트라면 그 컴포넌트와 함께 개발되지 않은 낯선 환경에서도 유용하게 쓰일 가능성이 크기 때문이다.

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

 

정보은닉의 기본원칙

가장 낮은 접근 수준을 부여해 줘야합니다.

 

접근 수준

  • private : 멤버를 선언한 톱 레벨 클래스에서만 접근할 수 있습니다.
  • package-private : 멤버가 소속된 패키지 안의 모든 클래스에서 접근할 수 있습니다.
  • protected : 멤버가 소속된 패키지 안의 모든 클래스와 하위 클래스에서 접근할 수 있습니다.
  • public : 모든 곳에서 접근할 수 있습니다.

 

접근 제어 방법

  • 먼저 공개 API는 pubclic으로 설계합니다.
  • 그 외의 모든 멤버는 private으로 설계합니다.
  • 같은 패키지의 다른 클래스가 접근해야 하는 경우 package-private으로 바꿔줍시다.

 

접근성 제약

상위 클래스의 메서드를 재정의 하는 경우, 그 접근 수준을 상위 클래스보다 좁게 설정할 수 없습니다.

이 제약은 상위클래스를 하위 클래스의 인스턴스로 대체해 사용할 수 있다는 원칙(리스코프 치환 원칙)을 지키기 위해서 필요합니다.

 

주의점

  • public 클래스는 상수용 public static final 필드 외에는 public 필드를 가져서는 안 됩니다. 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();
}

 

암묵적 접근 수준

Java 9 에서는 모듈 시스템이라는 개념이 도입되면서 2가지 암묵적 접근 수준이 추가되었습니다. 모듈이 공개 했는지 여부와 상관없이, public 혹은 protected 멤벌르 모듈 밖에서도 접근할 수 있게 됩니다. JDK는 이를 잘 활요하지만, 아직 모듈 개념이 널리 받아들여지지 않았기에 꼭 필요한 경우가 아니면 사용하지 말자

 

정리

  • 정보은닉을 위해 가장 낮은 접근 수준을 부여해 줍시다.
  • public 클래스는 상수용 public static final 필드 외에는 public 필드를 가져서는 안 됩니다.
  • publicl static fianl 필드가 참조하는 객체가 불변인지 확인합시다.
  • Java 9에 추가된 암묵적 접근 수준은 사용하지 맙시다.