class Point {
public double x;
public double y;
}
위와 같은 퇴보한 클래스는 데이터 필드를 직접 접근할 수 있음으로 캡슐화의 이점을 제공할 수 없다.
class Point {
private double x;
private double y;
public Point(double x, double y){
this.x = x;
this.y = y;
}
public double getx(){
return this.x;
}
public double gety(){
return this.y;
}
public void setx(double x){
this.x = x;
}
public void sety(double y){
this.y = y;
}
}
이렇게 패키지 바깥에서 접근할 수 있는 클래스라면 접근자를 제공함으로써 클래스 내부 변경을 유연하게 할 수 있다.
package-priavte 클래스 혹은 private 중첩클래스라면 데이터 필드를 노출한다 해도 문제가 되지 않는다
package-private 클래스
class Point {
public double x;
public double y;
}
해당 클래스가 package-private 접근자로 생성되었기에 같은 패키지 안에서만 값 접근 및 변경이 가능하다.
private 중첩 클래스
class Point {
private double x;
private double y;
public Point (double x, double y){
this.x = x;
this.y = y;
}
public void changeXY (double x, double y){
this.x = x;
this.y = y;
}
}
private 중첩 클래스임으로 같은 패키지 내에서만 해당 클래스 접근이 가능하면 값 변경 시 생성한 객체를 통해서만 접근 및 변경이 가능하다.
그래서 package-private 클래스보다 private 중첩 클래스가 더 제한적이다.
자바플랫폼 라이브러리에도 public 클래스의 필드를 직접 노출하지 말라는 규칙을 어긴 사례가 종종 있다.
대표적인 예로 java.awt 의 Point, Dimension 클래스이다.
public class Point extends Point2D implements java.io.Serializable {
/**
* The X coordinate of this <code>Point</code>.
* If no X coordinate is set it will default to 0.
*
* @serial
* @see #getLocation()
* @see #move(int, int)
* @since 1.0
*/
public int x;
/**
* The Y coordinate of this <code>Point</code>.
* If no Y coordinate is set it will default to 0.
*
* @serial
* @see #getLocation()
* @see #move(int, int)
* @since 1.0
*/
public int y;
/*
* JDK 1.1 serialVersionUID
*/
private static final long serialVersionUID = -5276940640259749850L;
이렇게 public으로 클래스 필드를 선언하면 성능이슈를 이르킨다. (해당 필드 변경시 다른 작업을 할 수 없음으로)
불변 필드를 public으로 선언 (유효한 시간 표현을 보장하는 클래스)
public final class Time {
private static final int HOUR_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 IllegalArqumentException("시간 : "+hour);
if (minute < 0 || minute >= MINUTES_PER_HOUR)
throw new IllegalArgumentException("분 : "+minute);
this.hour = hour;
this.minute = minute;
}
}
또한 불변 필드를 노출하는 public 클래스는 좋을까?
불변 필드를 public으로 선언한 경우엔 위에서 언급한 단점이 조금 줄어들긴 하지만, 결코 좋은 방법은 아니다.
왜냐하면 API를 변경하지 않고서는 표현 방식을 변경할 수 없고 필드를 읽을 때 부수 작업을 할 수 없는 단점은 여전히 존재하기 때문이다.
핵심 정리
public 클래스는 절대 가변 필드를 직접 노출해서는 안 된다.
불변 필드라면 노출해도 덜 위험하지만 안심할 수는 없다 하지만 package-private 클래스나 private 중첩클래스에서는
종종 (불변이든 가변이든)필드를 노출하는 편이 나을 때도 있다.
'IT > 자바' 카테고리의 다른 글
자바 플레이그라운드 with TDD, 클린코드 강좌 후기 Day 2 (0) | 2022.11.27 |
---|---|
자바 플레이그라운드 with TDD, 클린코드 강좌 후기 Day 1 (0) | 2022.10.31 |
[Effective Java] Item 15 클래스와 멤버의 접근 권한을 최소화하라 (0) | 2021.11.20 |
[Effective Java] Item 14 Comparable을 구현할지 고려하라 (0) | 2021.11.11 |
[Effective Java] item 10 equals는 일반 규약을 지켜 재정의하라 (0) | 2021.07.25 |