카테고리 없음

VO(Value Object)는 무엇이고 이것을 왜 사용하는 것일까?

_hanbxx_ 2024. 5. 14. 21:40
728x90

프로젝트 진행 중,  시작일과 종료일을 Embedded 객체로 따로 빼서 VO로 처리하는 코드를 짜보았다. 이 과정에서 VO의 정의 , 사용 이유 그리고 사용법에 대해 배울 수 있었다.

 

VO의 의미

도메인(엔티티)에서 한 개 또는 그 이상의 속성들을 묶어 특정 값을 나타내는 객체를 의미한다

 

VO 사용 이유

int, String과 같은 primitive 타입이 도메인 객체를 모델링하기 위해 충분하지 않다.

객체가 primitive 타입의 기능들을 전부 사용하지 않는다

유효성 검사 코드를 객체에 중복되는 부분들이 존재하는 모든 객체에서 검사 코드를 진행해야 할 것이다

 

VO 사용 시 제약 조건

  1. 불변성
    1. Setter와 가변 로직이 없는 불변 상태여야 한다
  2. 동등성
    1. 값이 같다면 동등한 객체로 판단해야 한다 
    2. 주소가 달라도 값이 같다면 동등한 객체로 판단해야 한다
    3. 즉, equals & hashCode를 재정의 해야 한다
  3. 자가 유효성 검사
    1. VO를 사용하면 VO 안에서 생성 시에 유효성 검사를 진행한 후에 생성되어야 한다.
    2. VO 내에 유효성 검사가 보장 되어 있으므로 안전하게 사용할 수 있다

코드 적용

@Getter
@Embeddable
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Period {
    private LocalDateTime startDate;

    private LocalDateTime endDate;

    @Builder(access = AccessLevel.PRIVATE)
    private Period(final LocalDateTime startDate, final LocalDateTime endDate) {
        this.startDate = startDate;
        this.endDate = endDate;
    }

    public static Period createPeriod(LocalDateTime startDate, LocalDateTime endDate) {
        validatePeriod(startDate, endDate);
        return Period.builder().startDate(startDate).endDate(endDate).build();
    }

    private static void validatePeriod(LocalDateTime startDate, LocalDateTime endDate) {
        if (startDate.isAfter(endDate) || startDate.isEqual(endDate)) {
            throw new CustomException(ErrorCode.DATE_PRECEDENCE_INVALID);
        }
    }


	//VO 변경 후 메소드 재정의
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Period that = (Period) o;
        return startDate == that.startDate && endDate == that.endDate;
    }

    @Override
    public int hashCode() {
        return Objects.hash(startDate, endDate);
    }
}
//VO 적용 전
    public static Recruitment createRecruitment(String name, LocalDateTime startDate, LocalDateTime endDate) {
        validatePeriod(startDate, endDate);
        return Recruitment.builder().name(name).period(period).build();
    }
    
    private static void validatePeriod(LocalDateTime startDate, LocalDateTime endDate) {
        if (startDate.isAfter(endDate) || startDate.isEqual(endDate)) {
            throw new CustomException(ErrorCode.DATE_PRECEDENCE_INVALID);
        }
    }

//VO 적용 후
    public static Recruitment createRecruitment(String name, LocalDateTime startDate, LocalDateTime endDate) {
        Period period = Period.createPeriod(startDate, endDate);
        return Recruitment.builder().name(name).period(period).build();
    }

 

 

 

출처 :

https://ksh-coding.tistory.com/83

 

VO(Value Object)는 무엇일까? 왜 사용할까?

1. VO(Value Object)란? VO의 의미를 보면 다음과 같다. * VO란 도메인에서 한 개 또는 그 이상의 속성들을 묶어서 특정 값을 나타내는 객체를 의미한다. * 해당 속성들을 primitive 타입이다! (int, boolean, ...

ksh-coding.tistory.com

 

728x90