有了Dish,为什么还定义DishVO和DishDTO?
在软件开发中,定义Dish、DishVO和DishDTO是为了遵循分层设计思想和单一职责原则,解决不同场景下的数据传递和展示问题。它们的核心区别在于使用场景和职责不同。
我们通过一个具体场景来理解 Dish(实体类)、DishDTO(数据传输对象)、DishVO(视图对象)的区别:
假设我们有一个菜品管理系统,数据库 dish 表结构如下:
sql
CREATE TABLE dish (
id BIGINT PRIMARY KEY AUTO_INCREMENT, -- 菜品ID
name VARCHAR(100) NOT NULL, -- 菜品名称
price DECIMAL(10,2) NOT NULL, -- 菜品价格
category_id BIGINT NOT NULL, -- 分类ID(关联分类表)
image VARCHAR(255), -- 图片路径
status INT NOT NULL, -- 状态(0-禁用,1-启用)
create_time DATETIME NOT NULL, -- 创建时间
update_time DATETIME NOT NULL, -- 更新时间
create_user BIGINT NOT NULL, -- 创建人ID
update_user BIGINT NOT NULL -- 更新人ID
);
1. Dish(实体类)
完全映射数据库表结构,用于和数据库交互:
java
public class Dish {
private Long id; // 对应表中id
private String name; // 对应表中name
private BigDecimal price; // 对应表中price
private Long categoryId; // 对应表中category_id
private String image; // 对应表中image
private Integer status; // 对应表中status
private LocalDateTime createTime; // 对应表中create_time
private LocalDateTime updateTime; // 对应表中update_time
private Long createUser; // 对应表中create_user
private Long updateUser; // 对应表中update_user
// getter/setter省略
}
使用场景:在 Service 层操作数据库时使用,例如 dishMapper.insert(dish) 保存数据到数据库。
2. DishDTO(数据传输对象)
用于接收前端传递的参数(按需定义,避免冗余):
示例 :新增菜品的 DishDTO
前端新增菜品时,无需传递 id(数据库自增)、createTime(后端生成)等字段,因此 DTO 只保留必要参数:
java
public class DishSaveDTO {
private String name; // 必须:菜品名称
private BigDecimal price; // 必须:菜品价格
private Long categoryId; // 必须:分类ID
private String image; // 可选:图片路径
private Integer status; // 必须:状态(0-禁用,1-启用)
// getter/setter省略
}
3. DishVO(视图对象)
用于返回给前端展示(包含前端需要的额外信息):
java
public class DishVO {
private Long id; // 菜品ID(前端需要)
private String name; // 菜品名称(前端需要)
private BigDecimal price; // 菜品价格(前端需要)
private String image; // 图片路径(前端需要展示图片)
private String categoryName; // 额外:分类名称(前端需要显示"热菜"而非categoryId)
private String statusStr; // 额外:状态文字(前端显示"启用"而非1)
// getter/setter省略
}
通过这种拆分,即使数据库表结构变化(如新增字段),只要前端需求不变,DTO 和 VO 可以无需修改,大大提高了代码的灵活性和可维护性。