▶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는 꼭 분리해서 사용
● 출처
- 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 |
댓글