ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Item 16: In public classes, use accessor methods, not public fields
    독서/Effective Java 2021. 12. 19. 00:06

    public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라.

     

    public 가변 필드 사용

    클래스의 데이터 필드에 직접적으로 접근할 수 있어서, 캡슐화의 장점이 무색해진다. 

    // 쓰면 안되는 방법
    class Point {
        public double x;
        public double y;
    }
    
    // 어디서 많이 본 스타일인데...
    @Slf4j
    class PointTest {
    
      @Test
      @DisplayName("이렇게 쓰지 마세요")
      void publicPointTest(){
        Point point = new Point();
        point.x = 0.01;
        point.y = 0.01;
        log.info("x:{}, y:{}", point.x, point.y);
      }
    }

    쓰지 말아야 하는 이유

    • 클래스의 데이터 필드에 직접 접근할 수 있다. -> 캡슐화의 이점(Item 15)을 사용하지 않는다.
    • API를 변경하지 않고 표현을 변경할 수 없다.
    • 불변성을 적용할 수 없다.
    • 필드에 액세스할 때 보조 조치를 취할 수 없다.

     

    private 가변 필드로 변경, public 접근 메서드로 연결

    강경한 프로그래머의 방법:

    private 필드와 public 접근자 메서드(getter)로 구성해 필드에 직접 접근하는 것을 차단한다.

    변경 가능한 클래스의 경우 mutator(setter)를 추가 구성해 변경이 가능하도록 한다.

    public class MutablePoint {
      private double x;
      private double y;
    
      public MutablePoint(double x, double y) {
        this.x = x;
        this.y = y;
      }
    
      public double getX() {
        return x;
      }
    
      public double getY() {
        return y;
      }
    
      public void setX(double x) {
        this.x = x;
      }
    
      public void setY(double y) {
        this.y = y;
      }
    }

     

    클래스가 패키지 외부에서 액세스 가능한 경우(공개적인 경우) 클래스의 내부 표현을 변경할 수 있는 유연성을 유지하기 위해 접근자 메서드를 제공해 데이터 필드를 노출하는 걸 방지하자.

     

    Data Fields를 노출 선언해도 되는 부분

    그러나 클래스가 package-private이거나 비공개 중첩 클래스인 경우 클래스에서 제공하는 추상화를 설명하는 적절한 작업을 수행한다고 가정하면 데이터 필드를 노출해도 문제 없다. 이 접근 방식은 클래스 정의와 이를 사용하는 클라이언트 코드 모두에서 accessor-method 접근 방식보다 덜 복잡하고, 클라이언트 코드는 클래스의 내부 표현에 묶여 있지만 이 코드는 클래스를 포함하는 패키지로 제한되기에 변경의 영역을 패키지 내부로 제한할 수 있다. private 중첩 클래스의 경우 변경 범위는 둘러싸는 클래스로 더욱 제한된다.

    -> 고로 노출해서 써도 된다(애초에 내부에서만 사용할 것이기 때문)

     

    문제가 되는 부분

    Java 플랫폼 라이브러리의 여러 클래스는 공용 클래스가 필드를 직접 노출하지 않아야 한다는 조언을 위반한다.

    Ex) java.awt 패키지의 Point 및 Dimension 클래스

     

    private 불변 필드로 변경, public 접근 메서드로 연결

    Public Class가 필드를 직접 노출하는 것은 결코 좋은 생각이 아니지만, 필드가 변경 불가능한 경우 덜 해롭다. API를 변경하지 않고 이러한 클래스의 표현을 변경할 수 없으며 필드를 읽을 때 보조 작업을 수행할 수 없지만 불변성을 적용할 수 있다.

     

    Ex)각 인스턴스가 유효한 시간을 나타내도록 보장하는 Time Class

    // Public class with exposed immutable fields - questionable
    public final class Time {
      private static final int HOURS_PER_DAY = 24;
      private static final int MINUTES_PER_HOUR = 60;
    
      public final int hour;
      public final int minute;
    
      public Time(int hour, int minute) {
        if (hour < 0 || hour >= HOURS_PER_DAY)
          throw new IllegalArgumentException("Hour: " + hour);
        if (minute < 0 || minute >= MINUTES_PER_HOUR)
          throw new IllegalArgumentException("Min: " + minute);
        this.hour = hour;
        this.minute = minute;
      }
      // ... // Remainder omitted
    }

     

    요약

    Public Classes는 가변적인 필드들을 드러내면 안된다, 불변 필드를 노출하는건 그래도 덜 해롭다.

    그러나 package-private classes 또는 private nested classes(중첩 클래스)는 변경 가능하거나 변경할 수 없는 필드를 노출하는 것이 나을 수 있다.

    댓글

Designed by Tistory.