📌 VO 패턴(Value Obejct pattern)
- 객체를 값처럼 쓸 수 있다.
- 객체의 인스턴스 변수가 생성자를 통해서 설정된 후에는 결코 변하지 않음을 보장한다. (불변객체)
- 별칭 문제에 대해 걱정할 필요가 없다.
- 별칭 문제 : 인스턴스 참조를 공유하는 복사본을 수정했을 때 원본이 같이 수정되는 현상
더보기
✒️ VO 패턴
가볍게 읽고 넘기려다가 재밌는 내용을 봐서 정리해보았다.
사람의 나이를 나타내기 위해서는 어떤 변수 타입을 나타내야 할까?
- Integer
- Boolean
- String
정답은 '없다'.
왜냐하면, Integer나 String은 age가 가지지 않는 속성과 연산들을 가지고 있기 때문이다.
두 나이를 더하거나 빼고, 곱하거나 나누고, 부정적 연령을 허용한다는 얼토당토 않는 연산이 가능해진다.
Domain 객체를 나타내기 위해 primitive 타입을 쓰는 나쁜 관습은 primitve obsession이라 불릴 정도로 흔하다.
따라서, 사람의 나이를 나타내기 위해서는 Age라는 사용자 선언 타입을 사용해야 한다.
- Immutability(불변성)
- Hassle-free Sharing (번거로움 없는 공유) : 참조로 자유롭게 공유
- Improved Semantics (향상된 의미) : 무의미한 Getter를 Value Object에 추가하지 않아야 한다.
- value equality(값 동등성)
- 동일성 : 식별자 기반으로 객체를 구분
- 동등성 : 상태를 기반으로 객체를 구분
- self validation(자가 유효성 검사)
- 생성자에서 유효성을 검사해야 한다.
- 모든 유효성 검사는 생성 시간에 이루어진다.
📌 동치성 검사
$5 + 10CHF = $10(환율이 2:1일 경우)$5 * $2 = $10
amount를 private로 만들기Dollar 부작용?
Money 반올림?
equals()
hashCode()
- $5는 $5와 언제나 같아야 한다.
- equals()를 구현할 때는 hashCode()를 같이 구현해야 한다.
@Test
void testEquality() {
assertTrue(new Dollar(5).equals(new Dollar(5)));
}
@Override public boolean equals(Object object) {
return true;
}
- 우선 가짜로 빨간막대를 확인하고 가짜로 구현하기 위해 true를 반환해놓자.
📌 삼각측량 기법
@Test
void testEquality() {
assertTrue(new Dollar(5).equals(new Dollar(5)));
assertFalse(new Dollar(5).equals(new Dollar(6)));
}
@Override public boolean equals(Object object) {
Dollar dollar = (Dollar) object;
return amount == dollar.amount;
}
- 라디오 신호를 감지하는 두 개의 수신국 사이의 거리와 각 수신국이 신호의 방향을 안다면, 라디오 신호의 거리와 방위를 알 수 있다.
- 즉, 예제가 두 개 이상 있다면 코드를 일반화할 수 있다.
- 두 번째 예가 좀더 일반적인 해를 필요로 할 때, 오로지 그때만 비로소 일반화한다.
- 삼각 측량은 조금 이상한 면이 있기에, 어떻게 리팩토링해야 할 지 전혀 감이 안 올 때 사용하면 좋다.
- 코드와 테스트 사이의 중복을 제거하고 일반적인 해법을 구할 방법이 보이는데 굳이 테스트를 또 만들 필요는 없다.
- 하지만 설계 방법이 떠오르지 않을 때면, 문제를 조금 다른 방향에서 생각해볼 기회를 제공한다.
📌 정리
$5 + 10CHF = $10(환율이 2:1일 경우)$5 * $2 = $10
amount를 private로 만들기Dollar 부작용?
Money 반올림?equals()
hashCode()
Equal null
Equal object
- 디자인 패턴(VO pattern)이 하나의 또 다른 operation을 암시한다는 것을 알았다.
- 해당 operation을 테스트 했다.
- 해당 operation을 간단히 구현했다.
- 곧장 리팩토링하는 대신 테스트를 조금 더 했다.
- 두 경우를 모두 수용할 수 있도록 리팩토링 했다.
- 해당 객체가 null이거나, 다른 객체와 비교하는 경우를 할 일 목록에 추가했다.