在软件开发中,尤其是面向对象编程和分层架构中,常常使用不同的数据对象来区分不同层次和不同职责的数据传输和处理。以下是 VO、DTO、DO、PO 的详细解释和举例说明:

1. VO(Value Object,值对象)

定义:VO 是一种不变的对象,通常用于表示某个数据的抽象,在系统中用于传递只读数据,常用于展示层。

特点

  • 不可变性:一旦创建,值对象的状态不能改变。
  • 无唯一标识:VO 不需要有唯一标识。

举例
假设我们有一个电商系统,需要在前端展示商品的详细信息。

public class ProductVO {
    private String name;
    private String description;
    private BigDecimal price;
    private String category;

    // 构造函数、getters 等省略

    public ProductVO(String name, String description, BigDecimal price, String category) {
        this.name = name;
        this.description = description;
        this.price = price;
        this.category = category;
    }
}

2. DTO(Data Transfer Object,数据传输对象)

定义:DTO 用于在不同层之间传输数据,通常用于服务层与控制层之间的数据传输。DTO 可以是可变的,通常包含 getter 和 setter 方法。

特点

  • 仅用于数据传输:不包含业务逻辑。
  • 可以包含部分业务逻辑以确保数据一致性。

举例
例如,在电商系统中,从客户端接收到创建订单的数据。

public class OrderDTO {
    private Long productId;
    private Integer quantity;
    private String customerName;
    private String shippingAddress;

    // 构造函数、getters 和 setters 省略

    public OrderDTO(Long productId, Integer quantity, String customerName, String shippingAddress) {
        this.productId = productId;
        this.quantity = quantity;
        this.customerName = customerName;
        this.shippingAddress = shippingAddress;
    }

    // Getters 和 Setters 省略
}

3. DO(Domain Object,领域对象)

定义:DO 代表领域模型中的对象,包含业务逻辑和规则,直接与数据库中的数据对应。它们在持久化层和业务层之间传递。

特点

  • 直接映射到数据库表。
  • 包含业务逻辑。

举例
在电商系统中,表示数据库中的订单记录。

public class OrderDO {
    private Long id;
    private Long productId;
    private Integer quantity;
    private String customerName;
    private String shippingAddress;
    private LocalDateTime orderDate;

    // 构造函数、getters 和 setters 省略

    public OrderDO(Long id, Long productId, Integer quantity, String customerName, String shippingAddress, LocalDateTime orderDate) {
        this.id = id;
        this.productId = productId;
        this.quantity = quantity;
        this.customerName = customerName;
        this.shippingAddress = shippingAddress;
        this.orderDate = orderDate;
    }

    // Getters 和 Setters 省略
}

4. PO(Persistent Object,持久对象)

定义:PO 通常是与数据库中的表结构一一对应的 Java 对象,用于持久化数据。通常使用 ORM 框架(如 Hibernate 或 MyBatis)进行映射。

特点

  • 映射到数据库表。
  • 包含持久化相关的注解。

举例
在电商系统中,表示数据库中的商品记录。

@Entity
@Table(name = "product")
public class ProductPO {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name")
    private String name;

    @Column(name = "description")
    private String description;

    @Column(name = "price")
    private BigDecimal price;

    @Column(name = "category")
    private String category;

    // 构造函数、getters 和 setters 省略

    public ProductPO(String name, String description, BigDecimal price, String category) {
        this.name = name;
        this.description = description;
        this.price = price;
        this.category = category;
    }

    // Getters 和 Setters 省略
}

5. 系统举例:

下面是一个使用 Spring Boot 和 MyBatis 构建的电商系统示例,包含商品和订单功能,展示了 VO、DTO、DO、PO 在三层架构中的具体应用。

项目结构

src/main/java
└── com/example/ecommerce
    ├── EcommerceApplication.java
    ├── controller
    │   ├── ProductController.java
    │   └── OrderController.java
    ├── service
    │   ├── ProductService.java
    │   └── OrderService.java
    ├── mapper
    │   ├── ProductMapper.java
    │   └── OrderMapper.java
    ├── domain
    │   ├── ProductDO.java
    │   └── OrderDO.java
    ├── po
    │   ├── ProductPO.java
    │   └── OrderPO.java
    ├── dto
    │   └── OrderDTO.java
    └── vo
        └── ProductVO.java

1. PO(Persistent Object)

映射数据库表,用于持久化数据。

// ProductPO.java
package com.example.ecommerce.po;

public class ProductPO {
    private Long id;
    private String name;
    private String description;
    private BigDecimal price;
    private String category;

    // Constructors, getters and setters
    public ProductPO() {}

    public ProductPO(String name, String description, BigDecimal price, String category) {
        this.name = name;
        this.description = description;
        this.price = price;
        this.category = category;
    }

    // Getters and Setters
}

// OrderPO.java
package com.example.ecommerce.po;

import java.time.LocalDateTime;

public class OrderPO {
    private Long id;
    private Long productId;
    private Integer quantity;
    private String customerName;
    private String shippingAddress;
    private LocalDateTime orderDate;

    // Constructors, getters and setters
    public OrderPO() {}

    public OrderPO(Long productId, Integer quantity, String customerName, String shippingAddress, LocalDateTime orderDate) {
        this.productId = productId;
        this.quantity = quantity;
        this.customerName = customerName;
        this.shippingAddress = shippingAddress;
        this.orderDate = orderDate;
    }

    // Getters and Setters
}

2. DO(Domain Object)

包含业务逻辑。

// OrderDO.java
package com.example.ecommerce.domain;

import java.math.BigDecimal;
import java.time.LocalDateTime;

public class OrderDO {
    private Long id;
    private Long productId;
    private Integer quantity;
    private String customerName;
    private String shippingAddress;
    private LocalDateTime orderDate;

    public OrderDO(Long id, Long productId, Integer quantity, String customerName, String shippingAddress, LocalDateTime orderDate) {
        this.id = id;
        this.productId = productId;
        this.quantity = quantity;
        this.customerName = customerName;
        this.shippingAddress = shippingAddress;
        this.orderDate = orderDate;
    }

    // Getters and Setters

    // Business logic methods
    public BigDecimal calculateTotalPrice(BigDecimal productPrice) {
        return productPrice.multiply(new BigDecimal(this.quantity));
    }
}

3. DTO(Data Transfer Object)

用于表示层和业务逻辑层之间的数据传输。

// OrderDTO.java
package com.example.ecommerce.dto;

public class OrderDTO {
    private Long productId;
    private Integer quantity;
    private String customerName;
    private String shippingAddress;

    public OrderDTO(Long productId, Integer quantity, String customerName, String shippingAddress) {
        this.productId = productId;
        this.quantity = quantity;
        this.customerName = customerName;
        this.shippingAddress = shippingAddress;
    }

    // Getters and Setters
}

4. VO(Value Object)

用于表示层展示数据。

// ProductVO.java
package com.example.ecommerce.vo;

import java.math.BigDecimal;

public class ProductVO {
    private Long id;
    private String name;
    private String description;
    private BigDecimal price;
    private String category;

    public ProductVO(Long id, String name, String description, BigDecimal price, String category) {
        this.id = id;
        this.name = name;
        this.description = description;
        this.price = price;
        this.category = category;
    }

    // Getters
}

5. Mapper(MyBatis Mapper)

// ProductMapper.java
package com.example.ecommerce.mapper;

import com.example.ecommerce.po.ProductPO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

@Mapper
public interface ProductMapper {
    @Select("SELECT * FROM product WHERE id = #{id}")
    ProductPO findById(Long id);
}

// OrderMapper.java
package com.example.ecommerce.mapper;

import com.example.ecommerce.po.OrderPO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Insert;

@Mapper
public interface OrderMapper {
    @Insert("INSERT INTO orders (product_id, quantity, customer_name, shipping_address, order_date) " +
            "VALUES (#{productId}, #{quantity}, #{customerName}, #{shippingAddress}, #{orderDate})")
    void save(OrderPO orderPO);
}

6. Service(业务逻辑层)

// ProductService.java
package com.example.ecommerce.service;

import com.example.ecommerce.mapper.ProductMapper;
import com.example.ecommerce.vo.ProductVO;
import com.example.ecommerce.po.ProductPO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class ProductService {

    @Autowired
    private ProductMapper productMapper;

    public ProductVO getProductById(Long id) {
        ProductPO productPO = productMapper.findById(id);
        return new ProductVO(productPO.getId(), productPO.getName(), productPO.getDescription(), productPO.getPrice(), productPO.getCategory());
    }
}

// OrderService.java
package com.example.ecommerce.service;

import com.example.ecommerce.mapper.OrderMapper;
import com.example.ecommerce.domain.OrderDO;
import com.example.ecommerce.dto.OrderDTO;
import com.example.ecommerce.po.OrderPO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;

@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;

    public void createOrder(OrderDTO orderDTO) {
        OrderDO orderDO = new OrderDO(null, orderDTO.getProductId(), orderDTO.getQuantity(), orderDTO.getCustomerName(), orderDTO.getShippingAddress(), LocalDateTime.now());
        OrderPO orderPO = new OrderPO(orderDO.getProductId(), orderDO.getQuantity(), orderDO.getCustomerName(), orderDO.getShippingAddress(), orderDO.getOrderDate());
        orderMapper.save(orderPO);
    }
}

7. Controller(表示层)

// ProductController.java
package com.example.ecommerce.controller;

import com.example.ecommerce.service.ProductService;
import com.example.ecommerce.vo.ProductVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/products")
public class ProductController {

    @Autowired
    private ProductService productService;

    @GetMapping("/{id}")
    public ResponseEntity<ProductVO> getProduct(@PathVariable Long id) {
        ProductVO productVO = productService.getProductById(id);
        return ResponseEntity.ok(productVO);
    }
}

// OrderController.java
package com.example.ecommerce.controller;

import com.example.ecommerce.dto.OrderDTO;
import com.example.ecommerce.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/orders")
public class OrderController {

    @Autowired
    private OrderService orderService;

    @PostMapping
    public ResponseEntity<String> createOrder(@RequestBody OrderDTO orderDTO) {
        orderService.createOrder(orderDTO);
        return ResponseEntity.ok("Order created successfully");
    }
}

8. 主应用程序类

// EcommerceApplication.java
package com.example.ecommerce;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.mybatis.spring.annotation.MapperScan;

@SpringBootApplication
@MapperScan("com.example.ecommerce.mapper")
public class EcommerceApplication {
    public static void main(String[] args) {
        SpringApplication.run(EcommerceApplication.class, args);
    }
}

结论

这个示例展示了如何使用 Spring Boot 和 MyBatis 实现一个电商系统的三层架构,分别使用 VO、DTO、DO 和 PO 来管理不同层次的数据对象。

  • PO(持久对象) 在数据访问层(DAO 层)中与数据库表进行映射和持久化。
  • DO(领域对象) 在业务逻辑层(Service 层)中包含业务逻辑。
  • DTO(数据传输对象) 用于表示层(Controller 层)和业务逻辑层(Service 层)之间的数据传输。
  • VO(值对象) 在表示层(Controller 层)中用于展示数据。

这种分层和对象的使用方式提高了系统的可维护性和可扩展性,使代码更清晰,职责分明。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐