개인 프로젝트를 진행하다가 회원가입 기능을 구현하는데 MemberForm을 따로 분리하여 구현하는 것과 폼 없이 엔티티를 직접 등록과 수정 화면에서 사용하는 것의 차이에 대해 궁금해졌고, 알아보기로 했다.
우선 간단하게 정의하자면 아래와 같다.
- DAO: DB에 접근하는 역할을 하는 객체
- DTO: 데이터를 전달하기 위한 객체
- VO: 값 자체를 표현하는 객체
1. DAO (Data Access Object):
- 특징
- DB에 접근하기 위한 객체
- 직접 DB에 접근하여 데이터 삽입, 삭제, 조회 가능(CRUD)
- DB에 접근하기 위한 로직과 비즈니스 로직을 분리하기 위해 사용
- DB와 연결할 Connection까지 설정되어 있는 경우가 많다.
- Service와 DB를 연결하는 고리 역할을 한다.
- Repository package가 DAO
- 예시
- 사용자 정보를 데이터베이스에서 가져오거나 업데이트하는 메서드를 포함한다.
이를 통해 애플리케이션은 데이터를 읽고 쓸 수 있다.
- 사용자 정보를 데이터베이스에서 가져오거나 업데이트하는 메서드를 포함한다.
- 사용하는 이유
- 효율적인 커넥션 관리와 보안성
- DAO는 비즈니스 로직을 분리하여 도메인 로직으로부터 DB와 관련한 메커니즘을 숨기기 위해 사용
import org.springframework.stereotype.Repository;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@Repository
public class UserDao {
@PersistenceContext
private EntityManager entityManager;
public User getUserById(Long userId) {
return entityManager.find(User.class, userId);
}
public void saveUser(User user) {
entityManager.persist(user);
}
}
2. DTO (Data Transfer Object) - 데이터 전송(이동) 객체
- 특징
- 데이터를 전달하기 위한 객체
- 로직을 가지지 않는 데이터 객체, getter와 seeter 메소드만 가진 클래스
- 계층간(Controller, View, Business Layer) 데이터 교환을 위한 자바 빈즈(Java Beans)를 의미
- 어떻게 구현하느냐에 따라 가변 객체로 활용할 수도 있고 불변 객체로 활용할 수도 있다.
- 비동기 처리할 때 사용
- 즉, DB의 데이터가 Presentation Logic Tier로 넘어올 때는 DTO로 변환되어 오고 가는 것
- 예시: 사용자 정보를 가진 DTO 객체를 만들어, 컨트롤러에서 서비스로 데이터를 전달할 때 사용한다.
/* 가변 객체 DTO
기본 생성자로 생성 후 값을 유동적으로 변경할 수 있음 */
public class UserDTO {
private String username;
private String email;
public String getUsername() {
return username;
}
public String getEmail() {
return email;
}
public String setUsername(String username) {
this.username = username;
}
public String setEmail(String email) {
this.email. = email;
}
}
/* 불변 객체 DTO
생성시 저장했던 값이 변하지 않고 getter() 메소드만 사용 가능 */
public class UserDTO {
private final String username;
private final String email;
public UserDTO(String username, String email) {
this.username = username;
this.email = email;
}
public String getUsername() {
return username;
}
public String getEmail() {
return email;
}
}
- 가변 객체 DTO를 만들 때는 setter()로 구현
- 불변 객체 DTO를 만들 때는 생성자를 이용해서 구현할 때 getter() 메소드만 구현
→ 이렇게 구현함으로 인해 데이터를 전달하는 과정에서 데이터 불변성 보장
3. VO (Value Object):
- 특징
- 값 자체를 표현하는 객체로 DTO와 유사
- getter() 메서드 뿐만 아니라 다른 비즈니스 로직도 포함할 수 있음
- 단순히 값 타입을 표현하기 위한 것으로 오로지 읽기 기능만 가능하다.(Read-Only)
- VO의 핵심정의: 두 객체의 모든 필드 값들이 동일하면 두 객체는 같다
- 완전히 값 자체 표현 용도로만 사용하는 게 목적
→두 객체의 모든 필드 값들이 모두 같으면 같은 객체로 만드는 것
- 완전히 값 자체 표현 용도로만 사용하는 게 목적
- equals()와 hashCode()의 오버라이딩이 중요하다.
- 예시: 날짜 범위나 좌표 같이 변경되지 않아야 하는 데이터를 VO로 표현할 수 있다.
@Getter @Setter
@Alias("article")
public class ArticleVO {
private Long id;
private String title;
private String contents;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Article article = (Article) o;
return Objects.equals(id, article.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
DTO vs VO
- DTO는 가변의 성격을 가진 클래스이며 데이터 전송을 위해 존재(getter and setter)
- VO는 값 그 자체의 의미를 가진 불변의 클래스(Read Only)(getter만 존재)
→ VO는 특정한 비즈니스 값을 담는 객체이고, DTO는 Layer간의 통신 용도로 오고가는 객체
4. Entity
- 특징
- 실제 DB의 테이블과 1:1로 매핑되는 클래스
- DB의 테이블 내에 존재하는 컬럼만을 속성(필드)로 가져야함.
- Entity를 기준으로 테이블이 형성되고 컬럼이 변경되곤 한다.
- 최대한 외부에서 Entity 클래스의 getter 메서드를 사용하지 않도록 해당 클래스 안에서 필요한 로직 메서드를 구현해야한다.
- Domain 로직만 가지며 Presentation 로직을 가져서는 안된다.
- 구현 메서드는 주로 Service Layer에서 사용한다.
- Entity를 데이터를 전달하는 클래스로 사용하면 안된다.
- 예시
// 객체 생성자 설정
@Builder
public Member(String username, String password, String name) {
this.username = username;
this.password = password;
this.name = name;
}
// 객체 생성 시 값 세팅(빌더패턴 사용)
Member member = Member.Builder()
.username("name")
.password("1234")
.name("name)
.build();
아래와 같이 기본 생성자 접근 제한자를 protected로 변경하면 new Member() 사용을 제한해 Entity의 일관성을 더 유지할 수 있다.
// Member 엔티티
@Entity
@Getter
@Table(name = "member")
public class Member{
// 기본 생성자 protected로 접근 제한(기본 생성자 접근 제한자는 protected 까지 허용
//기본 생성자의 접근 제한자를 private으로 걸면, 추후에 Lazy Loading 사용 시 Proxy 관련 예외가 발생)
protected Member(){};
...
}
// @NoArgsconstructor 어노테이션을 통한 protected 접근 제어.
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Table(name = "member")
public class Member {
}
Entity, DTO 클래스를 분리하는 이유
- DB Layer와 View Layer 사이의 역할을 분리하기 위함
- Entity 클래스는 실제 테이블과 매핑되어 만일 변경되게 되면 여러 다른 클래스에 영향을 끼침
→ DTO 클래스는 View와 통신하며 자주 변경되므로 분리해주어야 함
- 결론
- DTO는 Domain Model 객체를 그대로 두고 복사하여 다양한 Presentation Logic을 추가한 정도로 사용
- Domain Model 객체는 Persistent만을 위해 사용
Entity Setter 금지 및 생성자, 접근 제어
- Entity를 작성할 때 setter를 무분별하게 사용하면 객체(Entity)의 값을 변경할 수 있으므로 객체의 일관성을 보장할 수 없다.
- 객체의 일관성을 유지할 수 있어야 유지 보수성이 올라가기 때문에 setter를 사용해서는 안된다. 객체의 생성자에 값들을 넣어줌으로써 setter 사용을 줄일 수 있다.
Spring Boot Entity.class 예제 코드
@Getter
@Setter
@ToString
@Table(name = "user")
@Entity
public class User {
@Id
@GeneratedValue
private int id;
@Column(name = "name", nullable = false)
private String name;
@Column(name = "password", nullable = false)
private String password;
@Column(name = "email", nullable = false, unique = true)
private String email;
@Column(name = "phone", nullable = false, unique = true)
private String phone;
@Column(nullable = true)
private LocalDateTime create_date;
private LocalDateTime modify_date;
}
참고
- Domain Model 이란?
우선, 도메인 모델이란 애플리케이션의 핵심 비즈니스 객체를 나타낸다.
예를 들어, 은행 애플리케이션을 만든다고 상상해보자.
거기에는 '계좌(Account)'나 '거래(Transaction)'와 같은 중요한 객체들이 있을 텐데, 이런 객체들이 도메인 모델이 될 수 있다.
도메인 모델은 이러한 객체들의 데이터와 동작을 정의하고, 어떻게 상호작용하는지를 보여준다.
이걸 통해 비즈니스 로직을 더 잘 이해하고 구현할 수 있다.
도메인 모델은 데이터베이스와 관련이 있다.
사용자는 이 모델을 사용해 데이터베이스와 상호작용하고, 데이터를 저장하고 검색하는 등의 작업을 수행한다.
이런 모델을 사용하면 데이터베이스 스키마와 도메인 모델 간의 매핑을 관리하기 쉬워진다.
도메인 모델은 애플리케이션의 핵심이다.
- Presentation Logic이란?
프레젠테이션 로직은 사용자 인터페이스(UI)와 관련된 부분을 다루는 것.
이 부분은 사용자에게 정보를 보여주고, 사용자의 입력을 받아서 처리하고, 화면과 상호작용하는 역할을 한다.
- 첫 번째, 데이터 표시
프레젠테이션 로직은 비즈니스 로직에서 가져온 데이터를 화면에 보여준다.
텍스트, 이미지, 표 등으로 데이터를 꾸며서 사용자에게 제공함. - 두 번째, 사용자 입력 처리
사용자가 화면에서 무언가를 클릭하거나 입력하면 그에 대응하는 동작을 처리
사용자가 원하는 대로 애플리케이션을 조작할 수 있게 해준다. - 세 번째, UI 상태 관리
화면의 상태를 관리해야 한다.
화면 전환, 요소의 활성화/비활성화, 오류 메시지 표시 등을 다루는 부분을 말함. - 마지막으로, 이벤트 처리
사용자가 무언가를 클릭하면 그에 따라 어떤 동작을 해야 할지 정의하고 처리해야 함.
프레젠테이션 로직은 주로 프론트엔드에서 작동하고, 웹 애플리케이션에서 HTML, CSS, JavaScript를 사용해 구현됨.
이 부분을 잘 다루면 사용자 경험을 개선하고 애플리케이션의 외부 인터페이스를 향상시킬 수 있음
'CS' 카테고리의 다른 글
고정 소수점(fixed point)과 부동 소수점(floating point) (1) | 2024.01.25 |
---|---|
[CS] 슬라이싱 (0) | 2023.04.12 |
[CS] 라이브러리(library) (0) | 2023.04.06 |