본문 바로가기
개발 공부/Java

이펙티브 자바 아이템 16 - public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라 - 핵심 정리

by 개발인생 2022. 11. 14.
반응형

아이템 16 - public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라 - 핵심 정리

이 글은 백기선 님의 이펙티브 자바 강의와 이펙티브 자바 3 / E 편을 참고하여 작성하였습니다.

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

주의할 점은 public 클래스인 경우에 해당한다는 것이다.

public class Point {
   public double x;
   public double y;
}

위와 같이 public 필드를 사용하면 외부 클래스에서는

public class main {
   public static void main(String[] args) {
         Point point = new Point();
         point.x = 10;
         point.y = 20;

         System.out.println(point.x);
         System.out.println(point.y);
   }
}

직접 필드에 접근하여 값을 사용하게 된다.

이렇게되면 캡슐화의 장점 을 제공하지 못한다.

만약 필드명을 변경하게 된다면 Point 클래스를 사용하는 모든 코드들이 변경되어야 한다.

그리고 필드에 값을 할당할 때 제약 을 줄 수가 없다.

값을 가져갈 때 역시 부가적인 작업을 할 수 없다.

// 코드 16-2 접근자와 변경자(mutator) 메서드를 활용해 데이터를 캡슐화한다. (102쪽)
public class Point {
    private double x;
    private double y;

    public Point(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; }
}

위와 같이 모든 필드를 private 으로 바꾸고 getter, setter 메서드를 제공해준다.

이렇게하면 필드이름을 바꾸더라도 메서드 이름이 유지되기 때문에 유연하게 변경할 수 있다.

메서드 접근이기 때문에 부가적인 작업이 가능해진다.

만약 클래스가 package-private 인 경우에는 굳이 필드들을 private 으로 만들 필요가 없다.

그렇다하더라도 필드에 직접 접근보다는 public 한 메서드를 통해 필드에 접근하는 것이 이점이 더 많다.

// 코드 16-3 불변 필드를 노출한 public 클래스 - 과연 좋은가? (103-104쪽)
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;
    }

    // 나머지 코드 생략
}

final 키워드 를 사용한 불변으로 만든 필드를 노출하면 그나마 단점이 조금 줄어든다.

public 필드를 노출 하게되면 어디서 어떻게 값이 변경될지 알 수 없다.

떄문에 안전하게 사용하기 위해서는 해당 객체를 사용하는 쪽에서 값을 해당 scope 내에서 복사 해서 사용한다.

다른 메서드나 다른 객체에 넘겨주는 경우에 복사 를 사용한다.

public class main {
   public static void main(String[] args) {
         Point point = new Point();
         point.x = 10;
         point.y = 20;

         doSomething(point); // 값이 어떻게 변할지 알 수 없다.

         System.out.println(point.x);
         System.out.println(point.y);
   }
}

메서드 호출 후에 값이 어떻게 변경이 되었을지 알 수 없게된다.

public class main {
   public static void main(String[] args) {
         Point point = new Point();
         point.x = 10;
         point.y = 20;

         doSomething(point); // 값이 어떻게 변할지 알 수 없다.

         System.out.println(point.x);
         System.out.println(point.y);
   }

   private static void doSomething(Point point) {
      Point localPoint = new Point();

      localPoint.x = point.x;
      localPoint.y = point.y;
   }
}

안전하게 사용하기 위해서는 객체를 복사 하여 사용해야한다.

사실상 한번 public 으로 공개한 클래스는 어디서 사용하는지 알 수 없기 때문에 컨트롤하기가 불가능하다.

때문에 getter, setter 메서드를 제공해 필드에 접근할 수 있도록 해야한다.

반응형

댓글