浅谈 POJO 理解与应用
POJO
Plain Ordinary Java Object(普通 Java 对象)
用于区分 EJB,作为普通 Java 对象的简称。
根据使用场景分类:
-
数据库交互:DAO
-
实体:PO/Entity
-
业务:BO
-
数据传输:DTO
-
页面展示:VO
-
接口传参:Param
DAO
Data Access Object(数据交互对象)
- 含义:MVC 架构中的概念,作为 Service 和数据库的中间层。
- 作用:仅与数据库交互,不做其它业务功能。
PO
Persistent Object(持久对象)
也称 Entity(实体)
-
含义:从现实世界中抽象出来的业务实体,对应数据库的表结构。
-
内容:与数据库表字段一一对应。
(只用于数据的存取,不包含复杂操作。)
BO
Business Object(业务对象)
- 含义:对应一个业务的信息,在服务内部使用。
- 内容:对多个 PO 的封装(相同或不同类型)。
示例
- 查询用户的所有交易记录:
- PO:一条交易记录
- BO:所有交易记录
- 查询用户的所有信息:
- PO:PO1 是搜索记录,PO2 是浏览记录,PO3 是交易记录...
- BO:所有 PO。
DTO(❗)
Data Transfer Object(数据传输对象)
-
含义:在不同分层(或不同服务)的实体之间传输数据的对象,代表一个业务模块的输出。
- 不同分层:通常是 VO 与 PO/BO 之间的转换。
- 不同服务:在分布式/微服务架构中,远程调用的 API 接口返回的参数。
-
内容:目标实体的属性子集。
(从实体 A 转换为 B 时,由 DTO 提供 B 的字段信息。)
对比
- 对比 BO:
- BO 对服务内部使用,包含每个 PO 的完整信息。
- DTO 对外使用,在 BO 的基础上保留必要信息。
- 对比 VO:
- VO 返回给前端页面。
- DTO 作为远程调用的返回。
VO
View Object(视图对象)
- 含义:前端页面展示数据的对象。
- 内容:通常与 DTO 的属性定义相同(或是 DTO 的子集)
- 类似 DTO,但设计理念不同。
- 根据需要对 DTO 的值进行业务解释。
示例:业务解释
-
DTO:原始数据。
{ "name" : Jaywee, "gender" : 1, "age" : 40 }
-
VO:需要显示性别、年龄的别称。
{ "name" : Jaywee, "gender" : 男, "age" : 不惑 }
Param
入参封装(xxxParam)
- 含义:接口接收多个参数时封装 Param 对象,而不是定义多个形参。
- 内容:接口入参,根据业务可分为增删改查型。
- 增:xxxSaveParam
- 删:xxxRemoveParam
- 改:xxxEditParam
- 查:xxxQueryParam
- 要求:避免在接口定义多个形参,也避免使用 Map 作为入参。
示例:不同入参个数的形参编写。
// 无参数:查询所有用户
public List<User> listUsers();
// 单参数:查询指定年龄的用户
public User listUsersByAge(@RequestParam int age);
// 多参数:查询满足多个指定条件的用户
public List<User> listUsers(@RequestBody UserQueryParam query);
说明
DO
关于 DO 有两种版本,分别对应 PO 和 BO。
- 阿里巴巴开发手册:Data Object,对应上述 PO。
- 领域驱动设计(DDD):Domain Object,对应上述 BO。
POJO 与 Java Bean
Java Bean:可复用组件,具有一定要求。
- 公共的、非抽象的类。
- 私有属性、公共访问方法。
- 无参构造(Java Bean 通常由容器创建)
- 实现 Serializable 接口(实现持久性)
POJO:简单 Java 对象。
- 不准确理解:POJO 是一个只有属性及getter/setter 的 Java Bean。
- 较准确理解:POJO 泛指普通的 Java 对象。
实际使用
- 每个公司/项目有自己的规范,以上仅供参考。
- 通常在每个项目都会使用 DAO、PO、DTO。
- 小型项目中以 DTO 代替其它实体,可减少系统复杂程度及类的数量(如 BO、VO)。
转换工具
- MapStruct(👍)
- Simple Object Copy(IntelliJ IDEA 插件)