c23 [Spring] DTO, VO, Entity
본문 바로가기
[Spring]

[Spring] DTO, VO, Entity

by Jarvis2304 2025. 2. 18.

▶DTO(Data Transfer Object)

- 계층(Layer) 간에  데이터를 주고받을 때, 데이터를 전달하기 위해 사용하는 객체
- 데이터를 담아서 전달하는 바구니라고 생각할 수 있음

 

 

● 특징

-오직 getter/setter 메서드만 갖는다.

-순수하게 데이터를 전달하기 위한 객체이기 때문에 비즈니스 로직을 갖지않는다.

 

 

 


 

▷서버-클라이언트 DTO (Request/Response)

-DTO 내에서도 두 개의 다른 개념이 공존

 

1) 계층(Layer) 간에 데이터를 주고받을 때 사용되는 데이터 전달용 DTO

2) 서버-클라이언트 교환에 사용되는 DTO

 

-이 두 개념을 분리해야 한다

-만약 분리하지 않고 같이 사용한다면 서버-클라이언트 간 데이터 형태가 변경되면 DTO의 변경이 요구되면서, DTO가 변경되면 이를 참조하고 있는 Controller, Service, DAO 계층에 모두 영향을 받기 때문에 모두 변경해야 한다. 

-즉 같은 DTO로 사용하게 된다면, 계층은 클라이언트에 Dependency(의존성)가 생기게 됨 

 

▷DTO에서 Request/Response 객체 분리

-이러한 이유로 인해 DTO 중에서 서버-클라이언트 데이터 교환에 사용되는 DTO들을 Request/Response라는 이름으로 분리해서 사용

 

1) Request/Response 객체는 DTO의 한 종류

2) Request/Response 객체는 Presenter Layer(Controller)에서만 참조 가능

 

 

▷DTO를 쓰는 경우는?

  • 계층 간 데이터를 주고받아야 할 때
  • 클라이언트-서버 간의 요청(Request) 및 응답(Response) 데이터를 요청하고 응답할 때
  • 복잡한 비즈니스 로직 없이 단순히 데이터를 전달하는 목적일 때



 

 

 

VO(Value Object) 

-값 그 자체를 표현하는 객체

-값을 표현할 때 사용하며, 변경 불가능한 객체

-데이터를 전달할때도 사용

-값으로 비교되는 객체, VO에서는 주소 값이 달라도 데이터 값이 같다면 같은 객체로 취급함.   ex) 만원짜리 지폐에 쓰여져있는 고유번호(주소 값)이 달라도, 모두 같은 만원(데이터 값)으로 취급함

-일반적인 객체는 equals()와 hashcode() 메서드를 사용하면 모든 다른 객체로 판단하기 때문에, VO를 만들기 위해서는  equals()와 hashcode() 메서드를 오버라이드하여 구현해야 함 

 

 

● 특징

-불변객체이며, setter를 가질 수 없다. 생성자를 통해서만 값을 초기화해야 함

-비즈니스 로직을 가질 수 있다.

 

▷VO를 쓰는 경우는?

  • 데이터가 불변이어야하고, 단순히 저장된 값을 불러와야 하는 경우(Read-Only)
  • 데이터를 전달하거나 비교할때 사용
  • 값 자체가 중요한 경우   ex) 금액, 주소, 전화번호 등
  • 객체 간 비교가 필요한 경우   ex) 두 개의 금액을 비교하는 경우, 금액 객체는 VO로 구현)
  • 복합 객체의 일부로 사용될 경우 ex) 날짜 범위를 나타내는 객체가 있을 떄, 시작일과 종료일을 각각 VO로 구현

 

ex) VO 예시 코드

- Money 클래스를 통한 VO 예시 코드

- Money 객체는 setter가 없으므로 불변이며, 더하기나 뺄셈과 같은 비즈니스 로직은 가질 수 있음

- equals()와 hashcode() 메서드를 오버라이드하여 값이 같으면 같은 객체로 취급하도록 함

- amount 필드를 기반으로 해시 코드를 생성하여 두 Money 객체가 동일한 금액을 가질 때 동일한 해시 코드를 갖도록 함

// Money 클래스
public class Money {
    private final int amount;

    public Money(int amount) {
        this.amount = amount;
    }

    // 금액을 더하는 메서드
    public Money add(Money other) {
        return new Money(this.amount + other.amount);
    }

    // 금액을 빼는 메서드
    public Money subtract(Money other) {
        return new Money(this.amount - other.amount);
    }

    public int getAmount() {
        return amount;
    }



    // equals와 hashCode 메서드를 오버라이드하여 VO의 값 비교 기능 제공
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Money money = (Money) o;
        return amount == money.amount;
    }

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



 

 

 

 

 

 

▶ Entity(Domain)

-실제 DB 테이블과 1:1 매핑되는 객체

-즉, DB에 저장되어 있는 데이터(record)를 자바 객체로 1:1 매핑하여 클래스로 존재하는 데이터

-Entity 클래스는 DB와 매핑되어 있는 핵심 클래스이기 때문에 요청이나 응답값을 전달하는 클래스로 사용하면 안 됨

-Entity 클래스를 요청(Request)이나 응답(Response)을 전달하는 클래스로 사용한다면 View가 변경될때마다 Entity 클래스를 그에 맞춰 매번 변경해야 함.

-수 많은 서비스 클래스나 비즈니스 로직들이 Entity 클래스를 기준으로 동작하기 때문에 Entity 클래스를 변경하면 관련되어 있는 많은 클래스들에게 영향을 끼치게 됨

- 이러한 이유로인해 요청(Request) 이나 응답(Response)을 전달하는 클래스로는 View에 변경에 따라 다른 클래스들에게 영향을 끼치지 않고 자유롭게 변경할 수 있는 DTO를 사용 사용해야 함

- 사용자들에게 응답값으로 여러 테이블들을 조인한 결과값을 줘야 할 경우가 빈번하기 때문에 Entity 클래스로만 응답값을 표현하기 어려운 경우가 많음. 그렇게 때문에 Entity 클래스와 View 의 결과 값을 전달해 주는 DTO는 꼭 분리해서 사용

 

 

 

 

 

  출처

- Layered Architecture에서 데이터 클래스 분류: DTO, Entity, VO 적용과 DTO와 Request/Response 객체 분리 | by Quokkaman | Medium

- Entity vs DTO vs VO 개념 및 차이점 정리(with. 역할 분리) (tistory.com)

- https://www.youtube.com/watch?v=z5fUkck_RZM&t=319s

 

 

 

 

'[Spring]' 카테고리의 다른 글

[Spring] Restful API 설계 원칙  (0) 2025.02.13
[Spring] 스프링이란?  (1) 2025.02.11

댓글