개요
VO와 원시값 포장 객체는 유사한 점이 있지만, 다른 맥락에서 생긴 개념이다.
먼저 VO는 객체를 '값'으로 보기 위해서 만들어진 개념이다.
특정 객체 또는 값에게 타입을 부여해 해당 객체가 어떤 값을 표명하는지 쉽게 알 수 있게 해 준다.
이외에도 많은 이점을 누릴 수 있다.
원시값 포장 객체는 이름 그대로 primitive 타입을 포장한 객체다.
이 개념이 나오게 된 이유는 해당 값에 대한 책임을 분리하기 위해서이다.
VO(Value Object)
VO는 아래 3가지 조건을 만족해야 한다.
1. 동등성
2. 불변성
3. 자기 검증
동등성
VO는 한 가지 이상의 멤버를 가질 수 있다.
그리고 이를 값으로 보기 때문에 두 객체의 값이 같다면 같은 객체로 본다. 동등성이 보장되는 것이다.
VO로 설계된 카드 두 장을 비교한다고 해보자.
만약 두 카드의 모양과 숫자가 같다면 어떻게 될까?
같은 참조가 아니더라도 카드는 모양과 숫자로 구분된다. 같은 모양에 같은 숫자면 반드시 같은 카드로 봐야 한다.
따라서 VO는 동등성을 equals() 메서드와 hashCode() 메서드를 오바라이딩 해서 동등성을 비교할 수 있게 해줘야 한다.
불변성
VO는 불변성이 유지되어야 한다. 따라서 객체 생성 이후 내부 값의 수정이 이루어져선 안 된다.
만약 값이 변한다면 그 값을 범용적으로 사용할 수 있을까?
분명 한정적인 범위 내에서만 사용될 것이다.
반면에 값이 불변성을 가지면, 해당 값 객체가 위험 없이 공유될 수 있다.
자기 검증
만약 나이를 VO로 생성한다고 하자.
나이가 음수일 수 있을까?
이처럼 생성되는 과정에서 유효하지 않은 값에 대해 VO가 될 수 없다는 것을 알려줘야 하고,
이 책임은 해당 값을 가지는 VO에게 있다.
final class Age{
private final int age;
public Age(int value){
if(value < 1){
throw new InvalidAgeValue(value);
}
this.age = value;
}
}
원시값 포장 객체
원시값 포장 객체는 해당 원시값에 대한 책임을 담당하기 위해 나온 개념이다.
만약 원시값을 포장하지 않으면 그 값에 대한 책임이 분산될 것이다.
A라는 객체에서 원하는 그 값에 원하는 작업이 있고, B라는 객체에서 원하는 작업이 있다.
이렇게 한 값에 대한 책임이 분산되면 유지보수가 어려울 것이다.
하지만 그 값을 객체로 포장하면 A, B 객체에서 원하는 작업들
즉, 그 값의 책임을 한 객체에서 수행할 수 있다.
앞서 본 VO에서는 동등성과 불변성이 보장되어야 한다고 했다.
그렇다면 원시값 포장 객체도 그럴까?
그렇지 않다.
원시값 포장 객체는 동등성과 불변성이 보장될 필요가 없다.
쉽게 생각해 보면 값에 대한 불변성이 보장되어야 하지만,
그 값에 대한 책임을 담당해야 한다는 것 자체가 부자연스럽다.
또한 같은 값이라도 단지 값으로만 객체를 보는 것이 아니기 때문에
값에 대한 동등성을 부여하지 않아도 된다.
값에 대한 책임을 담당하기 위해 분리된 객체라는 것만 기억하면 될 것 같다.
마무리
사실 저도 위 두 개념을 알게 되고, 적용한 지 얼마 되지 않았습니다.
더 많이 사용해 보고 경험이 쌓일 때마다 글을 수정하거나 추가로 올리겠습니다.
잘못된 개념이나 피드백은 환영입니다 감사합니다 :)
참고
'JAVA' 카테고리의 다른 글
[JAVA] 상속과 조합 (1) | 2023.11.08 |
---|---|
[JAVA] equals(), hashCode() 재정의(동등성과 동일성) (0) | 2023.10.27 |
[JAVA] JVM 메모리 영역 (0) | 2023.06.13 |
[JAVA] 자바는 항상 Call-by-value로 동작한다? (0) | 2023.06.02 |