DTO vs VO vs Entity

배세훈·2021년 9월 11일
0

객체매핑차이

목록 보기
1/1

1. Entity란

Entity 클래스는 실제 DataBase의 테이블과 1:1 매핑 되는 클래스로 DB의 테이블내에 존재하는 컬럼만을 속성(필드)으로 가져야 한다.
Entity 클래스는 상속을 받거나 구현체여서는 안되며 테이블내에 존재하지 않는 컬럼을 가져서도 안된다.
서로 다른 Entity 내에 @ID로 구현된 속성의 값이 같다면 다른 속성들의 값이 달라도 같은 Entity이다.

Entity, DTO Class 분리 이유

Entity와 DTO를 분리해서 관리해야 하는 이유는 DB Layer와 View Layer 사이의 역할을 분리하기 위해서다.
Entity 클래스는 실제 테이블과 매핑되어 만일 변경되게 되면 여러 다른 클래스에 영향을 끼치고 DTO 클래스는 View와 통신하며 자주 변경되므로 분리 해주어야 한다.

무분별한 Setter 금지

엔티티를 작성할 때 습관적으로 모든 필드에 Setter를 생성하는 경우가 있습니다
하지만 Setter를 무분별하게 남용하다 보면 여기저기서 객체(엔티티)의 값을 변경할 수 있으므로 객체의 일관성을 보장할 수 없습니다.

그리고 setter는 그 의도를 알기 힘들다고 생각합니다.

예를 들어 아래 코드의 경우 멤버 객체를 set메소드를 통해 변경하는데 무엇을 하는건지 한번에 알 수 없습니다.

Member member = new Member();
member.setName("홍길동");
member.setTel("01012123333");
...
member.set...

아래 코드처럼 객체에서 메소드를 제공하여 변경하면 변경 의도를 한번에 알 수 있고 객체 자신의 값을 자신이 변경하는 것이 객체 지향 관점에도 더 맞는다고 생각합니다.

// 멤버의 기본정보를 수정한다는 것을 한눈에 알 수 있다.
member.changeBasicInfo("홍길동", "01012341234");

// Mmeber 엔티티 내부에 메서드 생성
public void changeBasicInfo(String name, String tel){
	this.name = name;
    this.tel = tel;
}

객체의 일관성을 유지하기 위해 객체 생성 시점에 값들을 넣어줌으로써 Setter 사용을 줄일 수 있습니다.

// 객체의 생성자 설정 (필드가 많을수록 롬복의 @Builder 사용하면 좋다)
@Builder
public Member(String username, String password, String name, String tel, Address adrress){
	this.username = username;
    this.password = password;
    this.name = name;
    this.tel = tel;
    this.address = address;
}
// 객체 생성 시 값 세팅(빌더패턴 사용)
Member member = Member.Builder()
	.username("name")
    .password("password")
    .tel("01012341223")
    .address(address)
    .build();

아래와 같이 기본 생성자 접근자를 protected로 변경하면 new Member() 사용을 막을 수 있어 객체의 일관성을 더 유지할 수 있습니다.
(protected로 설정하는 이유는 JPA 기본 스펙 상 기본 생성자가 필요한데 protected로 제어하는 것 까지 허용되기 때문입니다.)

// Member 엔티티
@Entity
@Getter
@Table(name="member")
public class Member{
	// 기본 생성자 protected로 접근 제어
    protected Member(){};
    ...
}

롬복을 사용한다면 @NoArgsconstructor 어노테이션 설정을 통해 간단하게 설정할 수 있습니다.

@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Table(name="member")
public class Member {

}

무분별한 Setter 사용금지는 엔티티 뿐 아니라 객체 생성 및 변경 시 모두 해당하는 부분입니다. 객체의 일관성을 유지할 수 있어야 프로그램의 유지 보수성을 끌어 올릴 수 있기 때문에 일급 컬렉션 사용 등 많은 개발자들이 객체의 일관성을 유지하기 위해 노력을 기울이고 있다고 생각합니다.

DTO(Data Transfer Object)

DTO(Data Transfer Object)는 데이터 전송(이동) 객체라는 의미를 가지고 있다. DTO는 주로 비동기 처리를 할 때 사용한다.

계층간 데이터 교환을 위한 객체(Java Beans)이다.
DB의 데이터를 Service나 Controller 등으로 보낼 때 사용하는 객체를 말한다.
즉, DB의 데이터가 Presentation Logic Tier로 넘어올때는 DTO로 변환되어 오고가는 것이다.
로직을 갖고 있지 않는 순수한 데이터 객체이며, getter/setter 메서드만을 갖는다.
또한 Controller Layer에서 Response DTO 형태로 Client에 전달한다.

VO(Value Obejct)

VO(Value Object)는 말 그대로 값 객체라는 의미를 가지고 있다.
VO의 핵심 역할은 equals()와 hashcode()를 오버라이딩 하는 것이다.
VO 내부에 선언된 속성(필드)의 모든 값들이 VO 객체마다 값이 같아야 똑같은 객체라고 판별한다.
서로 다른 이름을 갖는 VO 인스턴스더라도 모든 속성 값이 같다면 두 인스턴스는 같은 객체라고 할 수 있다. 이를 위해 VO에는 Object 클래스의 equals()와 hashCode()를 오버라이딩해야 한다.

VO는 Getter와 Setter를 가질 수 있으며 VO는 테이블 내에 있는 속성 외에 추가적인 속성을 가질 수 있으며 여러 테이블(A,B,C)에 대한 공통 속성을 모아서 만든 BaseVO 클래스를 상속받아서 사용할 수도 있다.

DTO vs VO

VO는 DTO와 동일한 개념이지만 read only 속성을 갖는다
VO는 특정한 비즈니스 값을 담는 객체이고 DTO는 Layer간의 통신 용도로 오고가는 객체를 말한다.

profile
성장형 인간

0개의 댓글