public 클래스의 public 필드의 사용(하지마라)
public class Point {
public double x;
public double y;
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);
}
}
위 예제의 public 필드는 아주 위험하다. 이런 클래스는 데이터 필드에 직접 접근이 가능하게되면서, API를 수정하지 않고는 내부 표현을 바꿀 수 없고, 불변식을 보장할 수 없고, 외부에서 필드에 접근할때 부수 작업을 수행할 수도 없다. 이를 아래의 private 필드의 사용 예제처럼 변경해야한다.
public 필드 사용시 문제가 없는 경우
package-private(=default) 클래스 혹은 private 중첩 클래스라면 데이터 필드를 노출한다해도 문제가 없다. 클라이언트 코드가 이 클래스를 사용한다 해도, 이 클래스를 포함하는 패키지 안에서만 동작하는 코드이므로, 패키지 바깥 코드에서는 데이터 표현 방식을 변경할 수 있다. private 중첩 클래스의 경우라면 수정 범위가 더 좁아져서 이 클래스를 포함하는 외부 클래스까지로 제한된다.
public 클래스의 private 필드의 사용(하라)
public class PointPrivate {
private double x;
private double y;
public PointPrivate(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
}
필드를 모두 private 로 변경하고, public 접근자 (getter/setter) 을 추가하였다. public 클래스에서라면 이 방식을 사용해야한다. 패키지 바깥에서 접근할 수 있는 클래스라면 접근자를 제공함으로써 클래스 내부 표현 방식을 언제든 바꿀 수 있는 유연성을 얻을 수 있다.
예외적으로 java.awt.package 패키지의 Point 와 Dimension 클래스(성능 이슈 존재)는 public 클래스임에도 public 필드를 사용중이다. 이 클래스들과 상관없이 우리는 public 클래스의 필드를 직접 노출하지 말라는 규칙을 지켜야한다.
Dimension.java
public class Dimension extends Dimension2D implements java.io.Serializable {
public int width;
public int height;
...
}
public final 필드
public class PointFinal {
private static final int HOURS_PER_DAY = 24;
private static final int MINUTES_PER_HOUR = 60;
public final int hour;
public final int minus;
/** 유효한 시간임을 보장 */
public PointFinal(int hour, int minus) {
if (hour < 0 || hour >= HOURS_PER_DAY) {
throw new IllegalArgumentException("시간 : " + hour);
}
if (minus < 0 || minus >= MINUTES_PER_HOUR) {
throw new IllegalArgumentException("분 : " + minus);
}
this.hour = hour;
this.minus = minus;
}
}
public 클래스가 필드를 공개하면 이를 사용하는 클라이언트가 생겨날 것이므로 내부 표현 방식을 마음대로 바꿀 수 없게된다. public 필드가 불변이라도 직접 노출할때의 단점은 불변성 외에는 모두 여전히 존재한다.
public final 로 선언된 필드는 인스턴스 생성 시점에서만 값이 셋팅된다. 생성자에 if 제어문을 추가하여 유효한 시간임을 보장할 수 있다.
'Book > Effective Java' 카테고리의 다른 글
[교재 EffectiveJava] 아이템 19. 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라 (0) | 2021.10.19 |
---|---|
[교재 EffectiveJava] 아이템 18. 상속보다는 컴포지션을 사용하라 (0) | 2021.10.18 |
[교재 EffectiveJava] 아이템 17. 변경 가능성을 최소화하라 (0) | 2021.10.17 |
[교재 EffectiveJava] 아이템 15-예제. static final array 변경하지 못하도록 설정하기 (0) | 2021.10.14 |
[교재 EffectiveJava] 아이템 15. 클래스와 멤버의 접근 권한을 최소화하라 (0) | 2021.10.14 |