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

제롬·2022년 2월 23일
0

이펙티브자바

목록 보기
16/25

접근자 메서드를 활용한 데이터 캡슐화

클래스 작성 실수: 인스턴스 필드만을 모아놓은 퇴보한 클래스

인스턴스 필드만을 모아놓은 클래스는 데이터에 직접 접근할 수 있으나 캡슐화의 이점을 제공하지 못한다.

[인스턴스 필드만을 모아놓은 클래스]

public class Point {
    public double x;
    public double y;
}
  • API를 수정하지 않고는 내부 표현을 바꿀 수 없다.
    • getter / setter 가 존재해야 내부 표현 변경이 가능하다.
  • 불변식을 보장하지 못한다.
    • 클라이언트가 데이터를 변경할 수 있다.
  • 외부에서 필드에 접근할 때 부수작업을 수행할 수 없다.

객체지향적인 클래스 작성: 데이터 캡슐화

객체지향적으로 클래스를 작성하기 위해서는 필드를 private으로 모두 바꾸고 public 접근자(getter)를 추가한다.

[public 접근자를 추가한 클래스 작성]

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

    public Point(final double x, final double y) {
        this.x = x;
        this.y = y;
    }

    public double getX() {
        return x;
    }

    public void setX(final double x) {
        this.x = x;
    }

    public double getY() {
        return y;
    }

    public void setY(final double y) {
        this.y = y;
    }
}
  • getter / setter 로 내부표현 변경이 가능하다.
  • 클라이언트는 public 메서드를 통해서만 데이터 접근이 가능하다.
  • 외부에서 부수작업을 수행시킬 수 있다.

package-private 클래스 혹은 private 중첩 클래스 데이터 캡슐화

package-private 클래스 혹은 private 중첩 클래스라면 데이터 필드를 노출한다 해도 클래스가 표현하려는 추상 개념만 올바르게 표현해주면 문제가 없다.

public class ColorPoint {
    private static class Point{
        public double x;
        public double y;
    }

    public Point getPoint(){ // 클라이언트 코드가 클래스 내부에 묶인다.
        Point point = new Point(); //ColorPoint 외부에서는 
        point.x = 1.2; // Point 클래스 내부 조작이 불가능하다.
        point.y = 5.3; 

        return point; 
    }
}
  • private(또는 package-private) 클래스를 중첩시키면 탑 클래스(제일 바깥 클래스) 외부에서는 Point 클래스의 필드에 접근하는 것이 불가능하다. 하지만, ColorPoint에서는 Point 클래스 필드 조작이 가능하다.
  • 클래스를 중첩시키는 방식은 클래스 선언 면에서나 이를 사용하는 클라이언트 코드면에서나 접근자 방식보다 깔끔하다.
  • 클래스를 중첩시키면 클라이언트 코드가 클래스 내부에 묶이기는 하지만 클라이언트도 어차피 이 클래스를 포함하는 패키지 안에서 동작하는 코드이므로 패키지 바깥 코드를 손대지 않고 데이터 표현방식을 바꿀 수 있다.
  • private 중첩 클래스의 경우 수정 범위가 더 좁아져서 이 클래스를 포함하는 외부 클래스까지로 제한된다.

public 클래스 필드 직접 노출 사례

자바 플랫폼 라이브러리에도 public 클래스의 필드를 직접 노출시키지 말라는 규칙을 어긴 사례가 존재한다. 대표적으로 java.awt.package 클래스의 PointDimension 클래스가 있다.

  • public 클래스 필드가 불변이라면 직접 노출할 떄의 단점이 조금은 줄어들지만, 여전히 좋은 코드가 아니다.
  • public 필드에 final 키워드를 추가해 불변으로 만들면 불변식은 보장할 수 있게 되지만 여전히 API를 변경하지 않고는 표현 방식을 바꿀 수 없고 필드를 읽을 때 부수작업을 수행할 수 없다는 단점은 변하지 않는다.

[불변 필드를 노출한 public 클래스]

public 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(final int hour, final int minute) {
        this.hour = hour;
        this.minute = minute;
    }   
}
...

결론

public 클래스는 절대 가변 필드를 직접 노출해서는 안된다. 하지만 package-private 클래스나 private 중첩 클래스에서는 종종 필드를 노출하는 편이 나을 때도 있다.

0개의 댓글