값 객체(Value Object)란?
1000원짜리 지폐 A와 1000원짜리 지폐 B가 있다.
- A와 B는 서로 다른 객체
- 하지만 둘 다 1000원이라는 가치를 가짐
A와 B가 다른 객체라는게 아니라 가지고 있는 값(value)가 중요!!
public final class Money {
private final long amount; // 불변성
public Money(long amount) {
if (amount < 0) throw new IllegalArgumentException("금액은 0 이상");
this.amount = amount;
}
public long amount() { return amount; }
@Override
public boolean equals(Object o) { // amount가 같으면 같다고 정의해주기
if (this == o) return true; // 자기 자신 통과
if (!(o instanceof Money other)) return false; // null 타입 거부 + 캐스팅
return amount == other.amount; // 의미상 동등성
}
@Override
public int hashCode() { // equals를 고치면 꼭 고쳐야 함!!
return Long.hashCode(amount);
}
}
* hashCode : HashMap의 키나 HashSet의 원소 쓰일 때, 기준이 되는 값.
값 객체(Value Object)의 장점
1. 불변성을 보장한다. (뒤에서 자세히 설명)
2. 가독성을 올려주고 실수를 방지한다.
public class Customer {
private final String name;
private Money money; // int → Money
public void pay(Money amount) { // int → Money
// …
}
}
코드를 위와 같이 수정하면, 코드만 봐도 변수가 돈을 의미한다는 것을 파악할 수 있고, 다른 int 값과 섞어 쓰는 실수를 막아준다.
불변성
값 객체는 변화하지 않는다는 성질을 가져야 한다. 그렇기 때문에 값 객체를 불변 객체로 만들어야 한다. 따라서 setter가 존재해서는 안되며, 가지고 있는 상태는 외부에 공개해서는 안된다.
불변 객체 3대 규칙
- 모든 필드 final + 생성자에서만 초기화
- 수정이 필요하면 새 객체 반환
- final class : 상속으로 우회하는 것을 막음
public final class Money {
private final long amount;
public Money(long amount) {
if (amount < 0) throw new IllegalArgumentException("금액은 0 이상");
this.amount = amount;
}
public long amount() { return amount; }
public Money add(Money other) {
return new Money(this.amount + other.amount);
}
public Money minus(Money other) {
if (this.amount < other.amount) {
throw new IllegalStateException("잔액 부족");
}
return new Money(this.amount - other.amount);
}
public boolean isLessThan(Money other) {
return this.amount < other.amount;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Money other)) return false;
return amount == other.amount;
}
@Override
public int hashCode() {
return Long.hashCode(amount);
}
}
* 불변을 적용한 Money 값 객체
값 객체를 불변으로 만들어야 하는 이유
- 별칭(alias) 버그 차단 : 같은 Money를 여러 곳에서 참조했을 때, 한 쪽이 바뀌면 바른 쪽이 조용히 따라 바뀌는 사고 차단
- equals / hashCode 무결성 : HashMap 키로 넣은 뒤 값이 바뀌면 원래 칸을 못 찾는 실패 방지(해시가 고정이므로)
불변의 장점
- 멀티 스레드 안전 (동기화 고민 없음)
- HashMap 키로 안전
'Java > 객체 지향' 카테고리의 다른 글
| 상속(Inheritance) VS 합성(Composition) (0) | 2026.06.15 |
|---|---|
| 방어적 복사 (0) | 2026.06.15 |
| 의존성 주입(Dependency Injection)과 조립자 (0) | 2026.06.12 |
| 객체 지향 원칙 4 - 다형성(Polymorphism) (0) | 2026.06.04 |
| 객체 지향 원칙 3 - 추상화 (0) | 2026.06.04 |