나를 기록하다
article thumbnail
Published 2023. 9. 3. 00:22
DAO, DTO, VO, ENTITY CS
반응형

스프링 부트.... 더욱더 봄이었다.

개인 프로젝트를 진행하다가 회원가입 기능을 구현하는데 MemberForm을 따로 분리하여 구현하는 것과 폼 없이 엔티티를 직접 등록과 수정 화면에서 사용하는 것의 차이에 대해 궁금해졌고, 알아보기로 했다.

우선 간단하게 정의하자면 아래와 같다.

  1. DAO: DB에 접근하는 역할을 하는 객체
  2. DTO: 데이터를 전달하기 위한 객체
  3. 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;
    }
}
  1. 가변 객체 DTO를 만들 때는 setter()로 구현
  2. 불변 객체 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)와 관련된 부분을 다루는 것.

이 부분은 사용자에게 정보를 보여주고, 사용자의 입력을 받아서 처리하고, 화면과 상호작용하는 역할을 한다.

  1. 첫 번째, 데이터 표시
    프레젠테이션 로직은 비즈니스 로직에서 가져온 데이터를 화면에 보여준다.
    텍스트, 이미지, 표 등으로 데이터를 꾸며서 사용자에게 제공함.
  2. 두 번째, 사용자 입력 처리
    사용자가 화면에서 무언가를 클릭하거나 입력하면 그에 대응하는 동작을 처리
    사용자가 원하는 대로 애플리케이션을 조작할 수 있게 해준다.
  3. 세 번째, UI 상태 관리
    화면의 상태를 관리해야 한다.
    화면 전환, 요소의 활성화/비활성화, 오류 메시지 표시 등을 다루는 부분을 말함.
  4. 마지막으로, 이벤트 처리
    사용자가 무언가를 클릭하면 그에 따라 어떤 동작을 해야 할지 정의하고 처리해야 함.
    프레젠테이션 로직은 주로 프론트엔드에서 작동하고, 웹 애플리케이션에서 HTML, CSS, JavaScript를 사용해 구현됨.
    이 부분을 잘 다루면 사용자 경험을 개선하고 애플리케이션의 외부 인터페이스를 향상시킬 수 있음

 

반응형

'CS' 카테고리의 다른 글

고정 소수점(fixed point)과 부동 소수점(floating point)  (1) 2024.01.25
[CS] 슬라이싱  (0) 2023.04.12
[CS] 라이브러리(library)  (0) 2023.04.06
profile

나를 기록하다

@prao

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

profile on loading

Loading...