이번 주제는 public으로 선언한 클래스에서 필드변수를 어떻게 선언해야 하는지에 대한 포스팅이다.
이전 포스팅에서 이번 주제에 대해 잠깐 설명했었다.
객체 필드변수는 절대로 public으로 선언하면 안 된다. 필드를 public으로 선언하면 필드에 저장될 값을 제한할 수 없게 되어 그 필드에 관계된 불변식을 강제할 수 없다. 그러므로 getter, setter와 같은 접근자 메서드를 사용하는 게 좋다.
좀 더 자세히 알아보자.
접근자 메서드
public class PositivePointWithPublicField {
// Can not limit value
public double x;
public double y;
public PositivePointWithPublicField(double x, double y) {
this.x = x;
this.y = y;
}
}
위 클래스는 x 와 y의 값이 모두 양의 값인 점을 표현하는 클래스이다. 하지만 x 와 y는 public이므로 클라이언트는 직접 조작할 수 있어 값이 음의 값이 될 수 있다. 또한 필드를 사용하는 순간에 어떤 동작이 실행되도록 만들 수도 없다. 이런 클래스는 아래와 같이 변경해주어야 한다.
public class PositivePointWithPrivateField {
private double x;
private double y;
public PositivePointWithPrivateField(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() {
// Any action can be performed
return x;
}
public void setX(double x) {
// Can limit value
if (x <= 0) {
throw new IllegalArgumentException();
}
this.x = x;
}
public double getY() {
// Any action can be performed
return y;
}
public void setY(double y) {
// Can limit value
if (y <= 0) {
throw new IllegalArgumentException();
}
this.y = y;
}
}
setter 메서드를 이용하여 필드의 값을 강제할 수 있으며 getter 메서드를 이용하여 필드를 사용하는 순간에 특정 동작을 수행하도록 할 수 있다.
package-private 클래스나 private 중첩 클래스는 public으로 선언해도 상관없다고 한다. 클래스가 정확히 어떤 클래스인지 기술만 한다면 말이다. 책 내용을 정확히 이해하지 못했지만, package-private 클래스나 private 중첩 클래스는 클라이언트에게 공개하는 API가 아니라 API를 구현하기 위한 클래스이므로 API 개발자가 잘만 쓰면 상관없다는 의미인 것 같다.
자바 클래스에서는 이 주제의 규칙을 지키지 않는 클래스들이 있다. 대표적으로 Point와 Dimension 클래스이다. 이런 클래스는 참고하지 않는 것이 좋다.
public class Point extends Point2D implements java.io.Serializable {
public int x;
public int y;
// ...
}
public class Dimension extends Dimension2D implements java.io.Serializable {
public int width;
public int height;
// ...
}