Java/Effective Java

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

메성 2020. 1. 4. 21:35
반응형

정보은닉과 접근제한자

정보은닉이란,

잘 설계된 컴포넌트는 바로 클래스 내부 데이터와 내부 구현 정보를 외부 컴포넌트로부터 얼마나 잘 숨겼느냐이다.

즉, 오직 API를 통해서만 다른 컴포넌트와 소통하고 서로의 내부 동작 방식에는 개의치 않는 것을 말한다.

 


 

그럼, 정보은닉의 장점을 살펴보자

  • 시스템 개발 속도를 높여준다. 여러 컴포넌트들이 독자적이어서 병렬로 개발할 수 있기 때문이다.
  • 시스템 관리 비용을 낮춰준다. 다른 컴포넌트로 교체하는 부담이 적기 때문이다.
  • 정보은닉 자체가 성능을 줄여주지는 않지만 성능 최적화에는 도움을 준다. 다른 컴포넌트에 영향을 주지않고 해당 컴포넌트만 최적화할 수 있는 기회가 생기기 때문이다.
  • 소프트웨어 재사용성을 높여준다. 외부에는 거의 의존하지 않고 독자적으로 동작할 수 있는 컴포넌트라면 낯선 환경에서도 재사용이 가능하다.
  • 시스템 전체가 완성되어있지 않더라도 개별 컴포넌트의 동작을 검증할 수가 있다.

그런데 이런 정보은닉을 제대로 사용하려면은 접근제한자를 잘 활용해야한다.

 

외적으로 정보은닉과 캡슐화에 대해서 헷갈리는 부분이 많은데, 정의해보자(간략히 살펴보자)

  • 정보은닉은 private을 사용하여 주요 사항이 드러나지 않도록 감추는 것이다.
  • 캡슐화는 메소드(Getter/Setter/public method)를 활용하여 외부에서 접근할 수 있는 부분만 설정한 후 외부와 직접적으로 소통하는 것을 말한다. 

 


 

클래스와 접근제한자

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

  • 소프트웨어가 올바로 동작하는 한 항상 가장 낮은 접근 수준을 부여해야 한다.

  • 톱레벨 클래스(클래스명)의 접근제한자는 public과 package-private만 사용할 수 있다.

    • public을 선언한 경우에는 공개 API가 된다.
    • package-private을 선언한 경우에는 해당 패키지 안에서만 사용 가능하다.
  • 멤버의 접근성을 좁히기 위한 클래스 구현 시 주의

    • 일단 처음에는 모든 멤버를 private으로 만들어야한다.
    • 같은 패키지에서 접근해야하는 멤버가 있을 시에는 package-private으로 변경한다.
    • 그러나, Serializable을 구현한 클래스에서는 의도치 않게 공개 API가 될 수도 있다.
    • 멤버의 접근 제한을 package-private에서 protected로 변경하는 순간 그 멤버에 접근할 수 있는 대상 범위가 넓어지니 주의해야한다. 따라서, protected 멤버의 수는 적을수록 좋다.
  • 멤버 접근성을 좁히지 못하게 하는 방해 제약

    • 상위 클래스의 메서드를 재정의할 때는 그 접근 수준을 상위 클래스에서보다 좁게 설정할 수가 없다.
      • 즉, 상위 클래스가 public, protected인데 하위클래스에서 재정의 시 package-private이나 private으로 변경이 불가능하다는 것이다.

 

  • 코드를 테스트하려는 목적으로 클래스, 인터페이스의 접근 범위를 결정할 때 주의해라
    • public 클래스의 private 멤버를 package-private까지 풀어주는 것은 상관이 없는데, 그 이상은 안된다. 그 이상은 공개 API가 될 수 있다.

 

  • public 클래스의 인스턴스 필드는 public이 아니어야 한다.
    • public 필드를 가지게 되면 불변식을 보장할 수 없으므로, thread safe하지가 않는다.
    • 상수라면 public static final 필드로 둬도 괜찮다. 단, 이 필드는 반드시 기본 타입 값이나 불변 객체를 참조해야 한다.

 

  • 클래스에서 public static final 배열 필드를 두지 마라

    public static final Thing[] VALUES = {...};
    //이 경우 배열내의 변경이 가능하다..
    • 배열 필드의 해결책
    //해결 1. 배열 필드를 private으로 선언 후 public 불변 리스트를 추가
    private static final Thing[] PRIVATE_VALUES = {...};
    public static final List<Thing> VALUES = Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));
    
    //해결 2. 배열 필드를 private으로 선언 후 그 복사본을 반환하는 public 메서드를 추가  
    private static final Thing\[\] PRIVATE\_VALUES = {...};  
    public static final Thing\[\] values() {  
    return PRIVATE\_VALUES.clone(); //방어적 복사본  
    }
    

 

정리

접근제한자를 활용하여 클래스와 멤버의 접근성을 최대한 좁히고, 독자적인 컴포넌트를 만드는 것이 정보은닉인 것이다.

반응형