카테고리 없음

VO와 DTO의 차이

유호야 2021. 7. 20. 01:21
반응형

DTO와 VO는 분명히 다른 개념이다. 그런데, 같은 개념으로 생각해서 사용하는 경우가 많다. 왜일까?
⌜Core J2EE Patterns: Best Practices and Design Strategies⌟ 책의 초판에서는 데이터 전송용 객체를 VO로 정의했다. 그 이후 2판에서는 해당 객체를 TO로 정정해서 작성했다. 이 때문에 DTO와 VO를 혼동하게 된 것 같다.
이번 글에서는 DTO, VO, Entity의 정의와 특징을 살펴본다. 마지막에는 세 객체를 도표로 비교하며 정리를 한다.

DTO(Data Transfer Object)

DTO는 데이터를 전달하기 위한 객체이다. 계층간 데이터를 주고 받을 때, 데이터를 담아서 전달하는 바구니로 생각할 수 있다. 여러 레이어 사이에서 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() 메소드를 오버라이딩 해줘야 한다.

아래 코드처럼 equals()와 hashCode() 메소드를 오버라이딩 하지 않으면 테스트가 실패한다.

// Money.java 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; } } // MoneyTest.java 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); } }

 

다음은 equals()와 hashCode() 메소드를 오버라이딩 하지 않았을 때의 테스트 결과이다.

 

한편, 두 메소드를 오버라이딩 하면 테스트가 통과한다. 앞서 말했듯이 VO는 주소가 아닌 값을 비교하기 때문이다.

// Money.java 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); } } // MoneyTest.java 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); } }

 

다음은 두 메소드를 오버라이딩 했을 때의 테스트 결과이다.

 

DTO vs VO vs Entity

DTO와 VO는 분명히 다른 개념이다. 그런데, 같은 개념으로 생각해서 사용하는 경우가 많다. 왜일까? ⌜Core J2EE Patterns: Best Practices and Design Strategies…

woowacourse.github.io

 

반응형