프로젝트를 진행하다가 DTO와 VO가 무엇인지 알아보게 되었는데 각자 정의하는 바가 달라 혼란스러워 일단 본인이 이해한대로 정리해보게 되었다.
(다만, 혼자만의 생각이니 틀린 부분이 있을 수 있다.)
학생이 사업단 근로 장학생을 신청할 때 재학 증명서, 성적 증명서, 신분증 사본, 통장 사본 등등이 필요하다고 할 때, 신청자는 이러한 것들을 모아서 제출하고 사업단 직원은 이를 받아볼 것이라는 시나리오를 짜보았다.
이제 이를 가지고 본인이 생각하는 Entity, DTO, VO를 뽑아볼 예정이다. 다른 부분은 생략하고 '통장 사본'에 중점을 둬볼 예정이다.
(참고로 getter, setter, Entity 생성 시 필요한 어노테이션 등은 이 글에서 생략했다.)
Entity는 실제 DB 테이블과 매핑되는 클래스다. Entity를 기준으로 테이블이 생성되고 스키마가 변경된다.
// 통장
public class Account {
Long id; // 고유 id
String accountNum; // 계좌 번호
String password; // 계좌 비밀번호
String ownerName; // 계좌 주인
...
// getter, setter
}
데이터를 담는 객체로 ReadOnly의 성향이 강해 setter는 사용하지 않는다. equals()랑 hashCode()를 오버라이딩하며 value가 같으면 같은 객체로 인식한다. VO는 주소가 아닌 값을 비교하게 된다.
// 통장 사본 (VO로 정의)
public class AccountVo {
String accountNum; // 계좌 번호
String ownerName; // 계좌 주인
...
// getter
// equals(), hashCode()
}
데이터는 Entity에도 있는데 왜 VO 클래스를 또 만든건지?
시나리오에서 학생이 제출해야 하는 것은 '통장' 자체가 아니라 '통장 사본'이다. 하지만 '통장'이라는 객체에는 비밀번호도 들어있는데, 사업단에서는 그 정보까지는 필요 없다.
또한, Entity 자체를 넘겨준다는 것은 실생활에서 봤을 때 본인 통장 그대로 들고 가서 제출하는 것과 유사한 상황이라고 생각한다.
데이터 전송에 쓰이는 객체이며 다른 비즈니스 로직에 전송할 때 사용한다. getter와 setter를 쓸 수 있으며 불변 객체로 쓰고싶을 경우 setter를 안쓰고 생성자를 이용해서 초기화하는 방법을 고려해볼 수 있다.
getter, setter 이외의 로직이 들어갈 수도 있다 vs 그렇지 않다 이렇게 갈리는 것 같은데 그 점에 대해서는 개발자 마음인 것 같다...!
// 제출 시 필요한 요소들의 집합에 대한 DTO
// 적절한 네이밍이 떠오르지 않아서...
public class FormDto {
AccountVo accountVo;
// 신분증 사본
// 성적 증명서
...
// getter, setter
}
이렇게 필요한 요소들을 담아서 request 및 response할 때 사용한다.
DTO와 VO는 엄연히 다르니 구분해야 한다 vs 비슷하니 통합해서 쓴다
이렇게 크게 갈리는 것 같다. 개념이 명확해지기 전까지는 계속 리서칭하고 게시글을 수정하면서 개선해볼 예정이다.