在 Java 项目里,这些对象都像“普通对象”,但职责不同。混用后,数据库结构、业务规则和接口返回容易耦合。可按“属于哪一层、放什么、不放什么”快速判断。
PO 和 DO:一个偏存储映射,一个偏领域表达
PO:面向数据库表的持久化对象
PO(Persistence Object)通常直接对应数据库表,服务于 ORM 或数据访问层,如 Hibernate、MyBatis。
- 职责:表示数据库中的一条记录。
- 特点:属性通常与表字段一一对应,一般不承载业务逻辑。
- 位置:DAO、Repository、Mapper 读写过程。
@Entity
@Table(name = "user")
public class UserPO {
@Id
private Long id;
private String username;
private String email;
// getters/setters
}
围绕“怎么存表、怎么取表”设计的类,更接近 PO。
DO:面向业务规则的领域对象
DO(Domain Object)强调业务语义。在 DDD 中,它不只是装数据,还可封装校验、状态变更和领域行为。
- 职责:表达领域模型,承载业务规则。
- 特点:可以有业务方法,不必完全按数据库字段设计。
- 注意:有些团队把 DO 解释为 Data Object,甚至等同于 PO,这属于命名差异。
public class UserDO {
private Long id;
private String username;
public boolean isValidUsername() {
return username != null && username.length() >= 6;
}
}
PO 关心“表里怎么存”,DO 关心“业务上它是什么、能做什么”。
BO:处理跨对象的业务聚合
BO(Business Object)用于复杂业务编排,重点是组织多个对象完成一段业务,而不是单表映射或单一实体本身。
- 职责:封装复杂业务逻辑。
- 特点:可能组合多个 PO 或 DO,一次处理多个实体关系。
- 场景:下单、结算、库存扣减、风控校验等跨实体流程。
public class OrderBO {
private OrderPO orderPO;
private UserPO userPO;
private List products;
public BigDecimal calculateTotalPrice() { ... }
}
DTO 和 VO:一个负责传输,一个负责展示
DTO:用于跨层或跨服务传数据
DTO(Data Transfer Object)用于不同层或不同服务之间传递数据,避免直接暴露内部模型。
- 职责:传数据,不写业务逻辑。
- 特点:结构常较扁平,可组合多个对象字段。
- 场景:Controller 和 Service 间入参/出参,微服务接口对象。
public class UserDTO {
private Long id;
private String username;
private String avatarUrl; // 可能由多个PO组合而来
// getters/setters
}
VO:贴近前端展示需求
Web 开发里常说的 VO,很多时候更偏 View Object,即返回给前端的展示对象。
- 职责:适配页面或接口展示。
- 特点:字段不一定对应数据库表,可能包含格式化后的日期、金额或状态文本。
- 场景:接口返回 JSON、列表页、详情页展示。
public class UserVO {
private String username;
private String formattedRegisterDate; // "2023-10-01"
// getters/setters
}
DTO 更关注“怎么传”,VO 更关注“怎么给前端看”。两者都不应承担核心业务规则。
五类对象怎么快速区分
| 对象 | 所在层次 | 核心职责 | 典型场景 |
|---|---|---|---|
| PO | 数据访问层 | 数据库映射 | MyBatis/Hibernate 操作数据库 |
| DO | 领域层 | 封装领域模型和业务规则 | DDD 中的实体对象 |
| BO | 业务逻辑层 | 复杂业务逻辑聚合 | 跨多个 PO/DO 的业务操作 |
| DTO | 传输层 | 跨层或跨服务传输数据 | Controller-Service 交互 |
| VO | 展示层 | 适配前端展示需求 | 返回前端的 JSON 数据 |
- 直接对表:优先想到 PO。
- 体现业务规则:优先想到 DO。
- 处理复杂流程:优先想到 BO。
- 用于层间传输:优先想到 DTO。
- 用于页面展示:优先想到 VO。
实际项目里怎么用,哪些地方最容易混
小型项目中,PO、DTO、VO 有时会合并使用,比如直接把 PO 作为接口返回对象。这样开发快,但数据库结构容易外泄,接口演进也会受限。
中大型项目通常更适合分层:
- PO 保持与数据库映射一致。
- DO 或 BO 承接业务规则,避免逻辑散落在 Controller 和 Mapper。
- DTO 负责层间或服务间传输,降低耦合。
- VO 单独面向前端,便于字段裁剪和格式化。
不同公司和框架的命名不完全统一。比如阿里规范中,DO 可能被当成 Data Object 使用,职责更接近 PO。判断时不能只看缩写,还要看它所在层次和实际职责。
对象转换很多时,可用 MapStruct、ModelMapper 减少样板代码,但它们解决的是“转换成本”,不是“职责边界”。
结语
PO、DO、BO、DTO、VO 的区别,本质上是分层职责的区别。项目越复杂,越需要拆开存储模型、领域规则、业务编排、传输对象和展示对象;简单项目也可按团队成本适度合并,但要明确这是权衡,不是默认混用。









