본문 바로가기
BackEnd/Java

[JAVA] DTO 와 VO의 차이점

by pplucy 2024. 3. 13.

 

자바를 사용하다보면 어느순간 DTO와 VO를 혼용하여 사용하는 경우들이 생겨나는데

이는 DTO와 VO를 명확하게 구분 짓고 않고 사용하기 때문에 발생하는 것이라고 본다.

( 나도 지금까지도 헷갈리고 있는 ... )

 

그래서 정리해본

DTO와 VO의 차이점


 

1. DTO의 개념

DTO는 'Data Transfer Object' 의 약자로 말 그대로 데이터 전달용 객체를 뜻한다.

 자세히 설명해보면 View-Controller-Service-Repository 와 같은 레이어(계층)간의 데이터 전달 시 사용하는 객체라고 할 수 있다.

DTO는 순수하게 '데이터 전달용' 객체이기 때문에 getter/setter를 제외하고는 어떠한 로직도 포함하고 있지 않는다는 것이 특징이다.

 

DTO에 setter 메소드가 생성된 경우 setter 를 통해 값이 가변적으로 바뀔 수 있기 때문에

계층간의 데이터 불변성을 보장해주기 위해서는 생성자를 사용하여 데이터 값을 초기화 해주는 것이 좋다.

 

Entity를 그대로 사용하지 않고 DTO를 사용하는 이유는, View에서의 비즈니스 요구사항은 자주 변경되는 부분이기 때문이다. Entity가 데이터 베이스와 직접적으로 매핑되는 중요한 클래스인만큼 Entity를 직접적으로 요청/응답 객체로 사용해서는 안된다.

 

Entity를 요청/응답 객체로 사용하게 되면, View의 비즈니스 요구사항이 변경될 때마다 Entity가 바뀌게 되고 Entity를 기준으로 동작하는 수많은 클래스들에게까지 사이드 이펙트가 나타날 수 있다.  또한 Entity 클래스 만으로는 응답값을 표현하기 어려운 경우도 많기 때문에 더욱 더 DTO 사용이 권장된다.

 

 

2. VO의 개념

VO는 'Value Object' 의 약자로 값을 표현하기 위한 객체를 뜻한다.

값 자체를 표현하는 용도로 사용되는 만큼 VO는 값의 불변성을 보장하여야 하기 때문에 setter가 생성되면 안되고 생성자를 통해 값이 초기화 되어야 한다.

VO에서의 중요한 개념은 같은 VO를 통해 만들어진 A와 B객체의 속성값이 모두 같다면, A와 B를 같은 객체로 본다는 개념이다.

 

값의 동등성을 비교하는 객체이기 때문에 VO 내에는 equals와 hashCode를 통해 값을 비교하는 로직이 포함되어야 한다. VO를 사용하게 되면 VO와 연관된 Class들의 결합도를 낮출 수 있으며, Entity의 속성값이 불필요하게 커지는 것도 방지할 수 있다.

또한 DTO와는 다르게 VO 내부에는 여러가지 비즈니스 로직이 추가될 수 있기 때문에 자가 유효성 검증이 가능해서 제약 조건 또한 보장 할 수 있게 된다.

 

 

* VO를 통한 자가 제약 조건 검증 시

// Before
public class MiddelShcoolStudent {
    private String name;
    private int age;
    private int grade;
    
    public MiddelShcoolStudent(String name, int age, int grade) {
        if( age < 14 || age > 16 ){
            // 나이 유효성 검사
        }
        if( grade < 1 || grade > 3){
            // 학년 유효성 검사
        }
        ....
    }
}

// After -> Age, Grade VO 생성
public class MiddelShcoolStudent {
    private String name;
    private Age age; // 유효성 검사
    private Grade grade; // 유효성 검사
    
    public MiddelShcoolStudent(String name, Age age, Grade grade) {
        this.age = age;
        this.grade = grade; 
    }
}

 

Entity에서 처리되었던 자가 제약 조건 검증이 VO를 통해 간결하게 처리된다.

 

 

* VO를 통한 객체 비교

// Car VO
public class Car {
    private String name;

    public Car( String name){
        this.name = name;
    }

    @Override
    public boolean equals(Object obj) {
        if( this == obj ){
            return true;
        }
        if( !(obj instanceof Car )){
            return false;
        }
        Car car = (Car)obj;
        return name == car.name;
    }

    @Override
    public int hashCode() {
        return Objects.hash(name);
    }
}

// TEST Passed
public class test {
    @Test
    public void testSameValue() {
        final String carName = "GV80";
        Car car1 = new Car(carName);
        Car car2 = new Car(carName);
        assertThat(car1).isEqualTo(car2);
        assertThat(car1).hasSameHashCodeAs(car2);
    }
}

 

값의 동등성을 비교했을 때 같은 속성값을 가지고 있는 car1과 car2는 같은 객체로 판명된다.

 

 

  DTO VO
description 레이어(계층)간 데이터 전달 값 자체 표현
값의 동등성 속성값이 모두 같아도 같은 객체가 아님 속성값이 모두 같으면 같은 객체
불변성 setter 가 존재하면 가변, 없다면 불변 불변
로직 포함 여부 getter/setter 외에 로직 포함 안됨 getter/setter 외에 로직 포함 가능

댓글