작성
·
94
·
수정됨
0
package lang.immutable.address;
public class ImmutableAddress {
private final String value;
public ImmutableAddress(String value) {
this.value = value;
}
public String getValue() {
return value;
}
@Override
public String toString() {
return "ImmutableAddress{" +
"value='" + value + '\'' +
'}';
}
}
ImmutableAddress 클래스는 value 필드를 final로 선언하고 값을 변경할 수 있는 setBalue()를 제거해 생성자를 통해서만 값을 생성할 수 있고, 이후에는 값을 변경하지 못하게 하였습니다. 이로 인해
public class RefMain2 {
public static void main(String[] args) {
ImmutableAddress a = new ImmutableAddress("서울");
ImmutableAddress b = a; //참조값 대입을 막을 수 있는 방법이 없다.
System.out.println("a = " + a);
System.out.println("b = " + b);
//b.setValue("부산"); //컴파일 오류 발생
b = new ImmutableAddress("부산");
System.out.println("부산 -> a");
System.out.println("a = " + a);
System.out.println("b = " + b);
}
}
RefMain2에서는 ImmutableAddress의 경우 b의 값을 부산으로 변경할 수 있는 b.setValue() 메서드가 제거되어 ImmutableAddress 인스턴스의 값을 변경할 수 있는 방법은 새로운 ImmutableAddress("부산") 인스턴스를 생성해서 b에 대입해야 한다고 알고 있습니다. 이로써 사이드 이펙트 문제를 해결할 수 있습니다.
그런데
package lang.immutable.address;
public class MemberV2 {
private String name;
private ImmutableAddress address;
public MemberV2(String name, ImmutableAddress address) {
this.name = name;
this.address = address;
}
public String getName() {
return name;
}
public ImmutableAddress getAddress() {
return address;
}
public void setAddress(ImmutableAddress address) {
this.address = address;
}
@Override
public String toString() {
return "Member{" +
"name='" + name + '\'' +
", address=" + address +
'}';
}
}
MemberV2의 경우 setAddrss 코드가 존재하고 main에서는
package lang.immutable.address;
public class MemberMainV2 {
public static void main(String[] args) {
ImmutableAddress address = new ImmutableAddress("서울");
MemberV2 memberA = new MemberV2("회원A", address);
MemberV2 memberB = new MemberV2("회원B", address);
//회원A, 회원B의 처음 주소는 모두 서울
System.out.println("memberA = " + memberA);
System.out.println("memberB = " + memberB);
//회원B의 주소를 부산으로 변경해야함
//memberB.getAddress().setValue("부산"); //컴파일 오류
memberB.setAddress(new ImmutableAddress("부산"));
System.out.println("부산 -> memberB.address");
System.out.println("memberA = " + memberA);
System.out.println("memberB = " + memberB);
}
}
setAddress를 통해서 memberB의 address에 접근할 수 있습니다. 새로운 ImmutableAddress 객체를 생성해야 하는 것은 맞지만 위 ImmutableAddress 코드와 모순이 발생합니다.
따라서 이 코드와 같이
package lang.immutable.address;
public class MemberV2 {
private final String name;
private final ImmutableAddress address;
public MemberV2(String name, ImmutableAddress address) {
this.name = name;
this.address = address;
}
public String getName() {
return name;
}
public ImmutableAddress getaddress() {
return address;
}
@Override
public String toString() {
return "MemberV2{" +
"name='" + name + '\'' +
", address=" + address +
'}';
}
}
package lang.immutable.address;
public class MemberMainV2 {
public static void main(String[] args) {
ImmutableAddress address = new ImmutableAddress("서울");
MemberV2 memberA = new MemberV2("회원A", address);
MemberV2 memberB = new MemberV2("회원B", address);
//회원A, 회원B의 처음 주소는 모두 서울
System.out.println("memberA = " + memberA);
System.out.println("memberB = " + memberB);
//회원B의 주소를 부산으로 변경해야함
//memberB.getAddress().setValue("부산"); //컴파일 오류
memberB = new MemberV2("회원B", new ImmutableAddress("부산"));
System.out.println("부산 -> memberB.address");
System.out.println("memberA = " + memberA);
System.out.println("memberB = " + memberB);
//회원B의 주소를 대전으로 변경
memberB = new MemberV2("회원B", new ImmutableAddress("대전"));
System.out.println("대전 -> memberB.address");
System.out.println("memberA = " + memberA);
System.out.println("memberB = " + memberB);
}
}
MemberV2의 name과 address를 final로 변경과 MemberV2에서 setAddress를 삭제하고 MemberV2 main에서 MemberV2 memberB = new MemberV2("회원B", new ImmutableAddress("부산")); 이렇게 코드를 수정해야 완벽한 불변성이 유지된다고 생각합니다.
실행 결과
답변 1
0
안녕하세요, 인프런 AI 인턴입니다.
vkvlditm00님께서 질문하신 불변 클래스에 대한 설명을 드리겠습니다.
ImmutableAddress 클래스가 불변성을 유지하기 위해 값을 변경할 수 있는 메서드(setValue 등)를 제거하고 final로 선언하여 외부에서 값을 변경할 수 없도록 설계되었습니다. 이를 통해 생성된 객체의 상태는 변경되지 않으며, 새로운 값을 할당하기 위해서는 새로운 인스턴스를 생성해야 합니다.
MemberV2 클래스의 경우 처음 작성하신 코드에서는 setAddress 메서드를 통해 address 필드를 변경할 수 있기 때문에 불변성을 유지하지 못합니다. ImmutableAddress 클래스와 같은 불변성을 유지하기 위해서는 MemberV2 클래스의 name과 address 필드를 final로 선언하고, setAddress 메서드를 제거해주는 것이 필요합니다.
MemberV2의 name과 address를 final로 선언하고, 변경이 필요할 때마다 새로운 객체를 생성하여 사용한다면, 불변성을 유지할 수 있습니다. 최종적으로 수정된 코드처럼 main 메서드에서 필요한 변경 사항마다 새로운 MemberV2 인스턴스를 생성하는 방법으로 사용할 수 있습니다.
이와 같이 사용하면 각 인스턴스의 상태가 불변하게 유지되며, 객체 참조가 변경될 때에도 기존 인스턴스는 그대로 유지됩니다.
도움이 되셨기를 바랍니다!
이미지 출처: Inflearn