[Back-end] DTO vs VO vs Entity

 

DTO, VO, Entity의 개념을 예제를 통해 상세히 학습하여 확실하게 짚고 넘어가려 한다.

 

✔️ DTO(Data Transfer Object)

DTO는 데이터를 전달하기 위한 객체이다. 계층간 데이터를 주고받을 때, 데이터를 담아서 전달하는 바구니로 생각할 수 있다. Spring을 학습하면서 다음 계층 관계도를 참고했었다.

KakaoTalk_Photo_2023-11-09-11-41-27.png

 

여러 레이어 사이에서 DTO를 사용할 수 있지만 주로 View와 Controller 사이에서 데이터를 주고받을 때 사용한다.DTO는 getter/setter 메서드를 포함한다. 이외의 비즈니스 로직은 포함하지 않는다.

 

아래 코드처럼 setter를 가지는 경우 가변 객체로 활용할 수 있다.

public class MemberDto {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

 

setter가 아닌 생성자를 이용해서 초기화하는 경우 불변 객체로 활용할 수 있다. 불변 객체로 만들면 데이터를 전달하는 과정에서 데이터가 변조되지 않음을 보장할 수 있다.

public class MemberDto {
    private final String name;
    private final int age;

    public MemberDto(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

 

 


 

✔️ VO(Value Object)

VO는 값 자체를 표현하는 객체이다. VO는 객체들의 주소가 달라도 값이 같으면 동일한 것으로 여긴다. 예를 들어 고유번호가 서로 다른 만원 2장이 있다면 이 둘은 고유번호(주소)는 다르지만 10000원(값)은 동일하다. VO는 getter 메서드와 함께 비즈니스 로직도 포함할 수 있다. 단, setter 메서드는 가지지 않는다. 또한, 값 비교를 위해 equals()와 hashCode() 메서드를 오버라이딩 해줘야 한다. 오버라이딩 하지않으면 테스트 결과가 실패한다.

public class Money {
    private final String currency;
    private final int value;

    public Money(String currency, int value) {
        this.currency = currency;
        this.value = value;
    }

    public String getCurrency() {
        return currency;
    }

    public int getValue() {
        return value;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Money money = (Money) o;
        return value == money.value && Objects.equals(currency, money.currency);
    }

    @Override
    public int hashCode() {
        return Objects.hash(currency, value);
    }
}

public class MoneyTest {
    @DisplayName("VO 동등비교를 한다.")
    @Test
    void isSameObjects() {
        Money money1 = new Money("원", 10000);
        Money money2 = new Money("원", 10000);

        assertThat(money1).isEqualTo(money2);
        assertThat(money1).hasSameHashCodeAs(money2);
    }
}

 


 

✔️ Entity

Entity는 실제 DB 테이블과 매핑되는 핵심 클래스이다. 이를 기준으로 테이블이 생성되고 스키마가 변경된다. 따라서 절대로 Entity를 요청이나 응답값을 전달하는 클래스로 사용해서는 안된다. 이는 DTO를 이용하면 된다. Entity는 id로 구분된다. 그리고 비즈니스 로직을 포함할 수 있다. Entity는 DTO처럼 setter를 가지는 경우 가변 객체로 활용할 수 있다.

public class Member {
    private final Long id;
    private final String loginId;
    private final String loginPw;

    public Member() {
    }

    public Member(Long id, String email, String password) {
        this.id = id;
        this.email = email;
        this.password = password;
    }
}

 


 

✔️ 세 객체 비교

분류 DTO VO Entity
정의 레이어 간 데이터 전송용 객체 값 표현용 객체 DB 테이블 매핑용 객체
상태 변경 여부 가변 또는 불변 객체 불변 객체 가변 또는 불변 객체
로직 포함 여부 로직 포함 X 로직 포함 O 로직 포함 O

 

 

위 내용은 다음 블로그를 참고하였습니다.

https://tecoble.techcourse.co.kr/post/2021-05-16-dto-vs-vo-vs-entity/

 

DTO vs VO vs Entity

DTO와 VO는 분명히 다른 개념이다. 그런데, 같은 개념으로 생각해서 사용하는 경우가 많다. 왜일까? ⌜Core J2EE Patterns: Best Practices and Design Strategies⌟ 책의 초판에서는 데이터 전송용 객체를 로 정의

tecoble.techcourse.co.kr