1. VO(Value Object)란?
VO(Value Object)는 값을 표현하는 객체로, 변경이 불가능(Immutable)하며 동일한 속성을 가지면 같은 객체로 간주됩니다.
VO의 주요 특징
- 불변성(Immutable) → 객체 생성 후 값 변경 불가
- 동등성(Equality) 비교 → 동일한 값을 가지면 같은 객체로 간주
- 로직을 포함할 수 있음 → VO 내부에서 관련된 비즈니스 로직을 처리 가능
JPA에서 VO를 활용하면 엔티티의 일관성을 유지하고, 중복된 값 로직을 제거할 수 있는 장점이 있습니다.
2. JPA에서 VO 패턴 적용 방법
(1) VO를 활용하지 않은 일반적인 엔티티 설계
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
private String city;
private String street;
private String zipcode;
}
위처럼 엔티티 내에 주소 관련 필드를 직접 추가하면, 여러 엔티티에서 동일한 값 관련 로직이 중복될 수 있습니다.
(2) VO를 적용한 엔티티 설계
JPA에서는 @Embeddable과 @Embedded를 사용하여 VO 패턴을 적용할 수 있습니다.
@Embeddable
public class Address {
private String city;
private String street;
private String zipcode;
protected Address() {} // 기본 생성자 필요
public Address(String city, String street, String zipcode) {
this.city = city;
this.street = street;
this.zipcode = zipcode;
}
}
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
@Embedded
private Address address;
}
VO 패턴 적용의 장점
✅ 재사용성 증가 → 여러 엔티티에서 동일한 값 객체를 재사용 가능
✅ 데이터 일관성 유지 → 동일한 값을 가지면 같은 객체로 관리
✅ 불변성 보장 → 값 변경이 불가능하여 안전한 데이터 모델링 가능
3. VO의 불변성 유지하기
VO는 값이 변경되면 안 되므로, Setter를 제공하지 않고, 생성자로만 값을 설정해야 합니다.
@Embeddable
public class Money {
private int amount;
protected Money() {}
public Money(int amount) {
if (amount < 0) {
throw new IllegalArgumentException("금액은 0 이상이어야 합니다.");
}
this.amount = amount;
}
}
이렇게 하면 Money 객체가 생성된 이후 값을 변경할 수 없으며, 잘못된 값이 들어가는 것도 방지할 수 있습니다.
4. VO를 활용한 비즈니스 로직 처리
VO 내부에 연산 로직을 추가하면 비즈니스 규칙을 보다 직관적으로 관리할 수 있습니다.
@Embeddable
public class DiscountRate {
private double rate;
protected DiscountRate() {}
public DiscountRate(double rate) {
if (rate < 0 || rate > 100) {
throw new IllegalArgumentException("할인율은 0~100% 사이여야 합니다.");
}
this.rate = rate;
}
public double applyDiscount(double price) {
return price * (1 - rate / 100);
}
}
이제 엔티티에서 applyDiscount() 메서드를 사용하여 할인된 가격을 쉽게 계산할 수 있습니다.
@Entity
public class Product {
@Id @GeneratedValue
private Long id;
private double price;
@Embedded
private DiscountRate discountRate;
public double getDiscountedPrice() {
return discountRate.applyDiscount(price);
}
}
'Back-End > JPA' 카테고리의 다른 글
JPA 3.0에서 새롭게 추가된 기능들 정리 (0) | 2025.03.09 |
---|---|
JPA와 NoSQL: MongoDB와 함께 사용 (0) | 2025.03.09 |
JPA에서 지연 로딩과 즉시 로딩의 차이 및 활용법 (0) | 2025.03.09 |
JPA 트랜잭션 관리와 @Transactional의 동작 방식 (0) | 2025.03.09 |
JPA랑 Hibernate (0) | 2025.03.09 |