JAVA/Effective Java

[아이템 16] public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라

꾸준함. 2024. 2. 1. 22:49

public 클래스 내 데이터 필드를 public으로 선언하여 직접 접근할 수 있게 할 경우 아이템 15에서 정리한 캡슐화의 이점을 취할 수 없습니다.

 

문제가 되는 이유

 

 

 

위 코드처럼 데이터 필드에 직접 접근할 경우 아래와 같은 문제점이 발생할 수 있습니다.

  • 필드를 변경할 때 API 또한 변경해야 함
  • 필드에 접근할 때 부가 작업 불가
  • 불변식을 보장할 수 없음

 

1. 필드를 변경할 때 API 또한 변경해야 함

 

필드명을 변경하려면 해당 필드를 사용하는 모든 코드를 수정해야 합니다.

그러나 클래스를 public으로 선언하면 이는 공개 API로 간주되어, 실제로는 사용 중인 클라이언트 코드를 완전히 파악하는 것이 사실상 불가능합니다.

 

2. 필드에 접근할 때 부가 작업 불가

 

클라이언트가 필드에 직접 접근하면, 해당 값에 대한 제어를 잃게 됩니다.

예를 들어, x 좌표를 0 이하로 설정할 수 없다는 정책을 정했다고 가정했을 때, 클라이언트가 x 필드에 직접 접근하여 0 이하로 설정하더라도 이를 막을 방법이 없습니다.

그러나 setter 메서드를 제공하는 경우 해당 메서드에서 x 좌표를 0 이하로 설정할 때 AssertionError를 던지는 등 예외처리가 가능해집니다.

이처럼 별도 메서드로 제공할 경우 검증과 같은 부가 작업이 가능해지고 보다 유연하게 코드를 작성할 수 있습니다.

 

 

3. 불변식을 보장할 수 없음

 

클라이언트가 직접 값을 변경할 수 있기 때문에 불변식을 보장하지 못하는 문제점이 있습니다.

물론 데이터 필드가 모두 가변 객체가 아니고 public final로 선언할 경우 불변식을 보장할 수 있지만 이 경우에도 1번 문제점이 존재하기 때문에 권장하는 방법은 아닙니다.

 

데이터 필드를 public으로 선언해도 문제가 되지 않는 경우

package-private 클래스나 private 중첩 클래스의 경우, 데이터 필드를 public으로 노출시켜도 문제가 되지 않습니다.

 

1. package-private 클래스

 

pakcage-private 클래스의 경우 패키지 외부에서는 접근할 수 없으며 해당 패키지를 사용하는 사용자만 쓰기 때문에 side-effect가 제한적일 수 있습니다.

 

2. private 중첩 클래스

 

중첩 클래스를 감싸는 외부 클래스에서만 중첩 클래스의 데이터 필드를 조작할 수 있고 그 외 클래스에서는 해당 필드들을 직접 접근할 수 없기 때문에 문제가 되지 않습니다.

 

 

 

 

 

그럼에도 불구하고 두 케이스 모두 부가 작업이 필요할 수 있기 때문에 필드에 접근할 때는 메서드를 통하는 것을 권장합니다.

 

자바 플랫폼 라이브러리에서 규칙을 어긴 사례

공교롭게도 자바 플랫폼 라이브러리에도 public 클래스의 필드를 직접 노출하지 말라는 규칙을 어긴 사레들이 존재합니다.

대표적인 예가 java.awt.package 패키지의 Point와 Dimension 클래스입니다.

 

 

 

Dimension 클래스

 

가변 필드를 public으로 노출시켰기 때문에 getSize()를 호출하는 모든 코드에서 방어적 복사를 위해 인스턴스를 새로 생성해야 하고 이는 성능 저하를 유발할 수 있습니다.

또한 모든 getter 메서드에 방어 복사 로직을 추가해야 하는 것도 문제점 중 하나입니다.

 

 

정리

가변 필드는 public 클래스에서 직접 노출되어서는 안 되며, 불변 필드의 경우에도 직접 접근보다는 메서드를 통한 접근을 권장합니다.

 

참고

이펙티브 자바
이펙티브 자바 완벽 공략 2부 - 백기선 강사님

반응형