Java, Immutable - 날짜 클래스를 불변하기
주어진 CCData 클래스는 불변이 아니어서 공유 참조한 경우 사이드 이펙트가 발생되고 있다. 불변 클래스를 만들어준다.
CCData.java
public class CCDate {
private int year;
private int month;
private int day;
public CCDate(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public void setYear(int year) {
this.year = year;
}
public void setMonth(int month) {
this.month = month;
}
public void setDay(int day) {
this.day = day;
}
@Override
public String toString() {
return "year=" + year + ", month=" + month +", day=" + day;
}
}
CCDateMain.java
public class CCDateMain {
public static void main(String[] args) {
CCDate data1 = new CCDate(2025,1,3);
CCDate data2 = data1;
System.out.println("data1 = " + data1);
System.out.println("data2 = " + data2);
data2.setMonth(3);
System.out.println("data2 의 3월로 변경");
System.out.println("data1 = " + data1);
System.out.println("data2 = " + data2);
}
}
출력 결과
data1 = year=2025, month=1, day=3
data2 = year=2025, month=1, day=3
data2 의 3월로 변경
data1 = year=2025, month=3, day=3
data2 = year=2025, month=3, day=3
data2.setMonth(3) 코드를 한 경우 3월로 변경 시 data2 날짜는 변경되었으나, 의도하지 않은 data1 날짜도 함께 변경되었다.
풀이
멤버 필드를 final 키워드를 붙이고 변경 메소드를 new 연산자로 반환하여 변경한다.
CCDate.java
public class CCDate {
private final int year;
private final int month;
private final int day;
public CCDate(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public CCData setDate(int year, int month, int day) {
return new CCDate(year, month, day);
}
@Override
public String toString() {
return "year=" + year + ", month=" + month +", day=" + day;
}
}
CCDateMain.java
public class CCDateMain {
public static void main(String[] args) {
CCDate data1 = new CCDate(2025,1,3);
CCDate data2 = data1;
System.out.println("data1 = " + data1);
System.out.println("data2 = " + data2);
data2 = data2.setDate(2025, 3, 3);
System.out.println("data2 의 3월로 변경");
System.out.println("data1 = " + data1);
System.out.println("data2 = " + data2);
}
}
setYear,setMonth,setDay 없애고 setDate 추가하여 풀어보았는데, 호출하는 입장에서 다시 객체를 생성하면 끝나는 것으로 보여 부분 변경하는Year,Month,Day 메소드를 추가하여 풀어본다.
재풀이
CCDate.java
public class CCDate {
private final int year;
private final int month;
private final int day;
public CCDate(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public CCDate withYear(int year) {
return new CCDate(year, this.month, this.day);
}
public CCDate withMonth(int month) {
return new CCDate(this.year, month, this.day);
}
public CCDate withDay(int day) {
return new CCDate(this.year, this.month, day);
}
@Override
public String toString() {
return "year=" + year + ", month=" + month +", day=" + day;
}
}
CCDateMain.java
public class CCDateMain {
public static void main(String[] args) {
CCDate data1 = new CCDate(2025,1,3);
CCDate data2 = data1;
System.out.println("data1 = " + data1);
System.out.println("data2 = " + data2);
data2 = data2.withMonth(3);
System.out.println("data2 의 3월로 변경");
System.out.println("data1 = " + data1);
System.out.println("data2 = " + data2);
}
}
출력 결과
data1 = year=2025, month=1, day=3
data2 = year=2025, month=1, day=3
data2 의 3월로 변경
data1 = year=2025, month=1, day=3
data2 = year=2025, month=3, day=3
사이드 이펙트가 발생되지 않고 정상적으로 변경한 것을 확인할 수 있다.