*출처
https://tecoble.techcourse.co.kr/post/2021-05-16-dto-vs-vo-vs-entity/
프로젝트를 진행하는데 VO와 DTO, ENTITY같은 말이 자주 들렸다.
추상적으로 남들 하는말만 귀에 담아서 대충 이해했었는데
프로젝트 진행에 자꾸 막히니깐 내가 기초를 잘 못잡은 건가? 싶어서 정리를 한번 해보려고 한다.
DTO
먼저 최근에 가장 많이 쓴 DTO는 데이터 전송 계층으로 알고 있다.
단순히 원하는 데이터만 주고 받으려고 ResponseDto, RequestDto와 같이 만들어서 사용했는데
말그대로 데이터 전송만이 목적이다 보니 레코드 타입으로 만들어서 아래처럼 작성했었다.
레코드(Record)?
*참조* https://velog.io/@conatuseus/Java-Immutable-Object%EB%B6%88%EB%B3%80%EA%B0%9D%EC%B2%B4 https://scshim.tistory.com/372 레코드란 뭘까? 프로젝트를 진행하던중 record라는 클래스를 사용하는걸 봤다. 매우 생소했고 뭐지
notenoughtime.tistory.com
public record BoardCreateRequestDto(
String title,
String content
){}
@Builder
public record BoardCreateResponseDto(
boolean success
){}
}
그럼 이제 DTO가 뭔지 알아보도록 하자.
DTO(Data Transfer Object)
DTO는 데이터를 전달하기 위한 객체이다. 계층간 데이터를 주고 받을 때, 데이터를 담아서 전달하는 바구니로 생각할 수 있다. 여러 레이어 사이에서 DTO를 사용할 수 있지만, 주로 View와 Controller 사이에서 데이터를 주고 받을 때 활용한다 .DTO는 getter/setter 메소드를 포함한다. 이 외의 비즈니스 로직은 포함하지 않는다.
라고 한다.
내가 작성한 위와 같은 코드의 경우 불변 객체인 record로 작성했기 때문에 데이터를 전달하는 과정에서 데이터가 변조되지 않음을 보장할 수 있다.
VO(Value Object)
VO는 값 자체를 표현하는 객체이다. VO는 객체들의 주소가 달라도 값이 같으면 동일한 것으로 여긴다. 예를 들어, 고유번호가 서로 다른 만원 2장이 있다고 생각하자. 이 둘은 고유번호(주소)는 다르지만 10000원(값)은 동일하다.
VO는 getter 메소드와 함께 비즈니스 로직도 포함할 수 있다. 단, setter 메소드는 가지지 않는다. 또, 값 비교를 위해 equals()와 hashCode() 메소드를 오버라이딩 해줘야 한다.
vo는 다음에 다시 추가하도록 하겠다.
Entity
Entity는 실제 DB 테이블과 매핑되는 핵심 클래스이다. 이를 기준으로 테이블이 생성되고 스키마가 변경된다. 따라서, 절대로 Entity를 요청이나 응답값을 전달하는 클래스로 사용해서는 안 된다.
Entity는 id로 구분된다. 그리고 비즈니스 로직을 포함할 수 있다.
package com.example.study.board.domain;
import com.example.study.support.MySchemaConstants;
import com.example.study.support.UuidBaseEntity;
import lombok.*;
import javax.persistence.*;
import java.time.OffsetDateTime;
import java.util.UUID;
import static com.example.study.support.Constants.DEFAULT_TIMEZONE_ID;
@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Table(
name = MySchemaConstants.TB_BOARD,
schema = MySchemaConstants.SCHEMA
)
public class Board extends UuidBaseEntity {
public UUID memberId;
public String nickName;
@Column(name = "board_num", insertable = false, updatable = false)
public Long boardNum;
public String title;
public String content;
// 빌더로 생성을 할 때 기본으로 넣어주는 값
@Builder.Default
public OffsetDateTime createdAt = OffsetDateTime.now(DEFAULT_TIMEZONE_ID);
public OffsetDateTime updatedAt;
public OffsetDateTime deletedAt;
}
위의 코드에서는 Id를 uuidBaseEntity에서 상속받아서 쓰기때문에 @Id 어노테이션을 사용해 만들지않았지만
원래는
public class Board {
@Id
public Long Id;
public UUID memberId;
public String nickName;
@Column(name = "board_num", insertable = false, updatable = false)
public Long boardNum;
public String title;
public String content;
// 빌더로 생성을 할 때 기본으로 넣어주는 값
@Builder.Default
public OffsetDateTime createdAt = OffsetDateTime.now(DEFAULT_TIMEZONE_ID);
public OffsetDateTime updatedAt;
public OffsetDateTime deletedAt;
}
와 같이 아이디를 정의해줘야한다.
세 객체 비교
분류DTOVOENTITY
정의 | 레이어간 데이터 전송용 객체 | 값 표현용 객체 | DB 테이블 매핑용 객체 |
상태 변경 여부 | 가변 또는 불변 객체 | 불변 객체 | 가변 또는 불변 객체 |
로직 포함 여부 | 로직을 포함할 수 없다. | 로직을 포함할 수 있다. | 로직을 포함할 수 있다. |