한글로 직역하면 값 객체. 말에서 오는 어감은 객체로서 가지는 값을 의미하는 것 같아 보인다. 그리고 실제로 공부해보면 거의 비슷하다.
예를 들어서, Age 는 어떤 데이터 타입에 넣어줘야할까? 아마 나같은 초보자들은 백이면 백 int
라고 대답할 것 같다. 근데 대답은 No.
int
에 넣으면 실수로 Age 를 변경할 여지는 없을까?
int
에 넣은 Age를 사칙연산으로 계산하려고 사용할까?
int
에 넣은 Age가 음수값을 가질때가 있을까?
그래서 바로 Age 라는 직접 정의한 데이터 타입에 넣어줘야한다. 이것을 Value Object라고 한다. 왜 이것이 Value Object인지는 특징을 살펴보면 더 잘 이해할 수있다.
Value Object (이하 VO) 는 불변이다. 이 말은 한번 값을 넣으면 값을 변경할 수 없다는 의미이고 setter을 가질 수 없다는 의미이다.
Immutability는 좋은 이점을 가져다 준다.
불변이라는 특징을 가지기 때문에, 한번 Age 값을 생성자에 넣으면 이 값이 바뀐다는 것을 걱정할 필요없다.
다른 말로, 어떤 VO이든 참조 형식으로 공유할 수 있다. 불변이라는 것은 다른 곳에서 값이 바뀌지 않는다. 특히, 멀티스레드 환경에서 그 이점은 더 증폭된다.
final class Name {
private String value;
public Name(String value) {
this.value = value;
}
}
위 코드는 생성자를 거쳐 값이 만들어진 후에 밖에서 value에 접근할 수 없다. 불변성👍
final class ComplexNumber {
private float realPart;
private float complexPart;
// 1. 생성자나 정적 메서드를 이용해서 새로운 인스턴스를 만든다
public static ComplexNumber zero() {
return new ComplexNumber(0, 0);
}
// 1. 생성자나 정적 메서드를 이용해서 새로운 인스턴스를 만든다
public ComplexNumber(float realPart, float complexPart) {
this.realPart = realPart;
this.complexPart = complexPart;
}
// 2. 그 인스턴스를 이용해서 또 다른 Value Object를 만든다.
public ComplexNumber add(ComplexNumber anotherComplexNumber) {
return new ComplexNumber(
realPart + anotherComplexNumber.realPart,
complexPart + anotherComplexNumber.complexPart
);
}
// 3. 생성된 인스턴스에서 내부 데이터를 추출한다
public String toString() {
return String.format("%f + %f i", realPart, complexPart);
}
}
그런데 참고로 이 // 2. 그 인스턴스를 ...
항목 코드를 자세히 보면 다른 VO 의 private 필드를 불러 올수있는 것도 확인할 수 있다.