Framework/SpringBoot

[Spring] VO와 BO, DAO, DTO란 무엇인가

hurlud 2024. 3. 24. 21:01
VO, BO, DAO, DTO는 소프트웨어 개발에서 주로 사용되는 용어들입니다. 각각의 용어는 소프트웨어의 다른 층에서 사용되는 객체들을 나타냅니다. 각각의 역할과 특징에 대해 간단히 설명해보겠습니다.

요약

  1. VO (Value Object):
    • VO는 값을 담는 객체를 나타냅니다. 주로 데이터베이스의 테이블에 대응되는 엔티티의 상태를 나타냅니다.
    • VO는 주로 불변(Immutable)하고, equals() 및 hashCode()와 같은 메서드를 오버라이드하여 객체의 동등성을 비교하는 데 사용됩니다.
  2. BO (Business Object):
    • BO는 비즈니스 로직을 처리하는 객체를 나타냅니다. 주로 비즈니스 규칙을 구현하고, 데이터를 처리하며, 다양한 계산을 수행하는 데 사용됩니다.
    • BO는 비즈니스 도메인에서의 객체를 나타내며, 비즈니스 규칙을 캡슐화하고 적용하는 데 사용됩니다.
  3. DAO (Data Access Object):
    • DAO는 데이터베이스와의 상호 작용을 담당하는 객체를 나타냅니다. 주로 데이터베이스에 접근하여 데이터를 검색, 삽입, 갱신, 삭제하는 데 사용됩니다.
    • DAO는 비즈니스 계층과 데이터 액세스 계층 간의 인터페이스를 제공하여, 비즈니스 로직이 데이터베이스에 직접 접근하지 않고도 데이터에 접근할 수 있도록 합니다.
  4. DTO (Data Transfer Object):
    • DTO는 데이터 전송을 위한 객체를 나타냅니다. 주로 여러 계층 간에 데이터를 전달하고 전송하기 위해 사용됩니다.
    • DTO는 데이터를 보유하는 역할로, 특히 원격 인터페이스(예: 웹 서비스)를 통해 데이터를 전송할 때 사용됩니다. 비즈니스 로직을 포함하지 않으며, 단순히 데이터의 전달 목적으로 사용됩니다.

이러한 객체들은 소프트웨어의 다양한 층에서 역할에 따라 사용됩니다. VO는 데이터를 나타내고, BO는 비즈니스 로직을 구현하고, DAO는 데이터 액세스를 처리하며, DTO는 데이터를 전송하거나 전달하는 데 사용됩니다.

 

 

예제와 함께 자세하게 살펴보겠습니다.

VO (Value Object)

VO(Value Object)는 주로 데이터의 불변성을 보장하고, 비즈니스 로직에서 사용되는 데이터 객체를 나타냅니다.

 

VO는 불변하기 때문에 Setter처럼 값을 변경하는 메서드(수정자)가 존재하면 안 됩니다. 값을 변경할 수 없으니 VO는 주로 읽기 전용 데이터를 표현합니다. 

 

Java 코드로 VO의 예시를 보여드리겠습니다.

public class UserVO {
    private Long id;
    private String username;
    private String email;

    // 생성자
    public UserVO(Long id, String username, String email) {
        this.id = id;
        this.username = username;
        this.email = email;
    }

    // Getter
    public Long getId() {
        return id;
    }

    public String getUsername() {
        return username;
    }

    public String getEmail() {
        return email;
    }

    // equals 및 hashCode 메서드 오버라이딩
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        UserVO userVO = (UserVO) o;
        return Objects.equals(id, userVO.id) &&
                Objects.equals(username, userVO.username) &&
                Objects.equals(email, userVO.email);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, username, email);
    }

    // toString 메서드 오버라이딩
    @Override
    public String toString() {
        return "UserVO{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", email='" + email + '\'' +
                '}';
    }
}


위 코드처럼 수정자(Setter)가 없고 읽기만 가능하도록 Getter 메서드만 존재합니다. 또한 필드의 데이터가 모든 같은 객체는 동일한 객체로 판단해야 하기 때문에 equals 와 hashCode메서드를 오버라이딩 해야 합니다.

 

BO (Business Object)

BO(Business Object)는 비즈니스 로직을 수행하는 객체를 나타냅니다. BO는 비즈니스 규칙을 캡슐화하고 적용하는 데 사용됩니다.

 

보통 BO는 데이터베이스의 엔티티와는 조금 다르게, 비즈니스 로직을 구현하는 데에 중점을 둡니다. 즉, VO에 비즈니스 로직이 추가된 것이 BO입니다.

public class OrderBO {
    public boolean placeOrder(Order order) {
        // 주문 유효성 검사 및 처리 로직
        if (order.isValid()) {
            // 주문 데이터베이스에 저장 및 기타 비즈니스 로직 처리
            // ...
            return true;
        } else {
            return false;
        }
    }

    public boolean cancelOrder(Order order) {
        // 주문 취소 처리 로직
        // ...
        return true;
    }

    public double calculateTotalPrice(Order order) {
        // 주문에 대한 총 가격 계산 로직
        double totalPrice = 0.0;
        // ...
        return totalPrice;
    }
}

 

DAO (Data Access Object)

DAO(Data Access Object)는 데이터베이스나 다른 영구 저장소에 접근하기 위한 객체입니다. 이 객체는 주로 데이터베이스와의 상호작용을 추상화하고 캡슐화하여 비즈니스 로직과 데이터 액세스 로직을 분리합니다. 

 

Spring에서는 Repository 인터페이스가 DAO입니니다. 

 

DAO는 주로 다음과 같은 기능을 수행합니다:

  1. 데이터베이스 연결 관리: 데이터베이스와의 연결을 설정하고 닫는 작업을 처리합니다.
  2. 데이터베이스 쿼리 수행: 데이터베이스로 쿼리를 보내고 결과를 받아오는 작업을 수행합니다.
  3. 데이터 조작: 데이터베이스에서 데이터를 검색, 추가, 수정, 삭제하는 작업을 수행합니다.
  4. 데이터베이스 트랜잭션 관리: 여러 개의 데이터 조작 작업을 하나의 논리적인 단위로 묶어서 원자성, 일관성, 격리성, 지속성을 보장합니다.

 

일반적으로 DAO는 인터페이스로 정의되며, 실제 데이터 액세스 로직은 해당 인터페이스를 구현한 클래스에서 구현됩니다. 

import java.util.List;

public interface UserDAO {
    void save(User user);
    User findById(Long id);
    List<User> findAll();
    void update(User user);
    void delete(Long id);
}

 

DTO (Data Transfer Object)

DTO(Data Transfer Object)는 데이터를 전송하기 위한 객체를 나타냅니다. 주로 여러 계층 간에 데이터를 전달하고 전송하기 위해 사용됩니다. DTO는 데이터베이스에서 직접 가져온 데이터나 외부 시스템과의 통신에서 사용되는 데이터를 나타내는 데 사용됩니다.

 

DTO는 데이터를 저장하고 전달하는 데 사용될 뿐 비즈니스 로직을 포함하지 않습니다.

public class UserDTO {
    public final String username;
    public final String email;
    public final String password;

    // 생성자
    public UserDTO(String username, String email, String password) {
        this.username = username;
        this.email = email;
        this.password = password;
    }
}

 

엔티티가 있는데 왜 DTO를 사용해야 해?

Spring에서 간혹 RequstBody나 ResponseBody에 엔티티를 그대로 사용하는 경우가 있습니다. 

 

하지만 다음과 같은 이유들로 인해 엔티티와 DTO를 구분하여 사용하는 것이 좋습니다.

 

  1. 레이어 간의 분리: Entity는 주로 데이터베이스와 관련된 비즈니스 로직을 포함하는데 반해, DTO는 클라이언트와의 통신을 위한 데이터 전송 객체입니다. 이는 레이어 간의 역할 분리를 촉진하고, 각각의 역할에 맞는 책임을 부여하여 시스템을 더 깔끔하고 확장 가능하게 만듭니다.
  2. 불필요한 정보 노출 방지: Entity는 데이터베이스 스키마에 직접적으로 매핑되어 있기 때문에, 필요하지 않은 속성이나 민감한 정보가 클라이언트로 전달될 수 있습니다. DTO를 사용하면 클라이언트가 필요로 하는 정보만을 선택적으로 전송할 수 있으며, 보안과 프라이버시를 보다 쉽게 관리할 수 있습니다.
  3. 네트워크 트래픽 감소: Entity는 종종 연관된 엔티티를 로드하는 데 지연될 수 있는 연관된 객체 그래프를 가지고 있습니다. 이러한 경우, 클라이언트에 필요한 데이터만 포함된 DTO를 사용하면 네트워크 트래픽을 줄일 수 있습니다. 특히 모바일 애플리케이션과 같이 대역폭이 제한된 환경에서는 이러한 최적화가 더욱 중요합니다.
  4. API 버전 관리: Entity는 시스템의 핵심 데이터 구조를 나타내기 때문에 변경될 가능성이 높습니다. 이에 반해 DTO는 API의 인터페이스로 사용되기 때문에 API 버전 관리에 용이합니다. 새로운 버전의 API를 도입할 때 기존의 Entity를 변경하지 않고 DTO를 조정함으로써 버전 관리를 보다 유연하게 할 수 있습니다.
  5. 클라이언트 종속성 감소: Entity는 데이터베이스와 강하게 결합되어 있기 때문에, 클라이언트 코드가 데이터베이스 스키마에 직접적으로 의존하게 됩니다. 이는 클라이언트 코드의 유지 보수와 변경을 어렵게 만들 수 있습니다. DTO를 사용하면 클라이언트가 독립적으로 동작할 수 있도록 하여 종속성을 최소화할 수 있습니다.