본문 바로가기
Languages/Java

DTO vs VO 그리고 Entity와 DTO를 분리하는 이유

by yoon_seon 2023. 4. 26.

DTO와 VO를 당연 시 사용했지만 막상 DTO와 VO의 차이에 대해 뚜렷하게 설명할 수 없었고 이번 포스팅을 통해 정리해보려고 한다.

 

먼저, DTO와 VO는 전혀 다른 용도의 객체이다.

 

📌 VO 란?

VO는 Value Object로 값 그 자체를 표현하는 객체이다. VO는 객체의 참조값이 다르더라도 값이 같다면 동일한 것으로 봐야한다.

예를 들어 서로 고유번호가 다른 10000원 지폐가 2장이 있다고 할 때, 10000원 지폐의 고유 번호가 서로 다르다고 해서 다른 10000원 이라고 하지 않고 똑같은 10000원이라 한다. 이처럼 값으로만 비교되는 객체를 VO라고 한다.

 

📌 VO의 특징.

  • Read-Only속성을 가진다.
  • 값 자체를 표현하기 때문에 불변 객체여야한다.
  • 불변성이 보장되어야 하기 때문에 setter 메서드가 포함되지 않는다.
  • 비즈니스 로직이 포함될 수 있다.
  • equals()와 hashCode() 메서드를 오버라이딩하여 사용해야한다

 

equals()와 hashCode() 메서드를 오버라이딩하여 사용해야하는 이유

값 자체를 표현하기 때문에 주소 값이 다르더라도 값이 같으면 같은 값으로 봐야한다.

Hash의 이름을 갖는 컬렉션 프레임워크(HashSet, HashMay, HashTable)는 두 객체가 동등한지 비교할 때 hashCode의 리턴값을 먼저 비교하고 같으면 equals로 한 번 더 비교한다.

그래서 완전한 VO로 만들기 위해선 객체를 속성값 들로만 비교하도록 equals()와 hashCode() 메서드를 오버라이딩하여 사용해야한다.

 

 

📌 DTO 란?

DTO는 Data Transfer Object로 계층(Layer)간 데이터를 전달하기 위한 객체이다.

Web Layer에 해당하는 컨트롤러와 Serivce Layer에 해당하는 서비스가 있다.

계층 사이에서 데이터를 전달하기 위해 DTO에 데이터를 담아 서로 주고 받는다.

 

📌 DTO의 특징

  • DTO는 순수하게 데이터 전달 만을 위한 객체이다.
  • 순수한 데이터 객체로 비즈니스로직을 갖지 않는다.
  • 오직 getter/setter 메서드만을 갖는다.
    setter 생성 : setter 메서드로 새로운 값을 넣어 데이터가 가변적이다.
    setter 제한 : 생성자를 통해 속성값들을 초기화하게 만들어 불변 객체로 만들면 DTO가 전달하는 데이터가 전달 과정 중에 변조되지 않음을 보장하여 불변성을 보장할 수 있다.(개발자가 의도적으로 엉뚱한 값을 객체로 만들어 새로 전달하지 않는한)

간단한 예제로 이해해보자.

public class UserDTO {
    private String email;
    private String nickName;
    
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public String getNickName() {
        return nickName;
    }
    public void setNickName(String nickName) {
        this.nickName = nickName;
    }
}

email과 password 필드만 가지고 있는 UserDTO 클래스가 있다. UserDTO 클래스는 getter / setter만 가지고 있다.

 

public UserDTO saveUser() {
    String email = "123@tistory.com"
    String nickName = "닉네임"
    
    UserDTO userDTO = new UserDTO();
    userDTO.setEmail(email);
    userDTO.setNickName(nickName);
    
    return userDTO;
}

이 데이터를 보내주는 Serivce Layer에서 UserDTO 객체를 생성하고 setter를 통해 전달하고자 하는 데이터를 담아 반환해준다.

 

public String saveUser() {
    UserDTO userDTO = sampleService.saveUser();
    String email = userDTO.getEmail();
    String nickName = userDTO.getNickName();
    return "email : " + email + " nickName : " + nickName
}

이처럼 데이터를 받은 Web Layer에서 UserDTO 객체를 반환받아 getter를 통해 전달받은 데이터를 꺼내서 사용할 수 있다.

 

📌 DTO vs VO

  VO DTO
용도 값 자체를 표현 레이어 간 데이터를 전달
동등 결정 속성값이 모두 같으면  같은 객체로 봄 속성값이 아닌 주소값으로 비교해야한다
가변 / 불변 불변 setter 존재 시 가변,
setter 비 존재 시 불변
로직 모든 필드값 동등에 따른 객체들의 동등의 여부가 중요하지,
비즈니스 로직은 있으나 없으나 상관없다.
(setter 성격의 메소드 제외.)
DTO로만 사용하면 getter/setter 외의
비즈니스 로직은 필요없다.

 

 

📌 Entity와 DTO를 분리해야하는 이유? 

Entity 클래스는 데이터베이스와 매핑되어 있는 핵심 클래스이며 Entity 클래스를 기준으로 테이블이 생성되고 스키마가 변경된다. 

수많은 서비스 클래스나 비즈니스 로직들은 Entity 클래스를 기준으로 동작하고 Entity 클래스를 변경하면 관련된 모든 클래스들이 영향을 받는다.

 

View는 비즈니스 요구사항에서 자주 변경되는 부분이다. 만약 View가 변경될 때마다 Entity 클래스를 그에 맞춰서 매번 같이 변경한다면 Entity 클래스를 기준으로 동작하는 수많은 서비스 클래스나 비즈니스 로직들이 영향을 받을 수 밖에 없다.

그렇기 때문에  Entity 클래스 절대로 요청이나 응답 값을 전달하는 클래스로 사용하면 안된다.

 

따라서 요청이나 응답값을 전달하는 클래스로는 반드시 View에 변경에 따라 다른 클래스들에게 영향을 끼치지 않고 자유롭게 변경할 수 있는 DTO를 사용해야한다.

 

 

꼭 Entity클래스와  DTO를 분리해서 사용하자.

 

 


출처 : 우아한테크 인비의 DTO vs VO

댓글