一篇文章讲清楚 VO,BO,PO,DO,DTO 的区别

引言

在分层架构的约束下,在职责分离的指引下,一个软件系统需要定义各种各样的对象,在分层架构中承担了不同的职责,又彼此协作,共同响应系统外部的各种请求,执行业务逻辑,并让整个软件系统能够真正地跑起来。
然而,若没有真正理解这些对象在架构中扮演的角色,承担的职责,导致误用和滥用,就有可能适得其反。因此,有必要在领域驱动设计的方法体系下,将各式各样的对象进行一次梳理,形成一套统一语言,就不至于出现理解上的分歧,使用上的不当。由于这些对象皆以O结尾,故而戏称为XO对象。

术语解释

VO( View Object):显示层对象,通常是Web向模板渲染引擎层传输的对象。

BO( Business Object):业务对象。 由Service层输出的封装业务逻辑的对象。

DO( Data Object):与数据库表结构一一对应,通过DAO层向上传输数据源对象。 == PO == Entity

DTO( Data Transfer Object):数据传输对象,Service或Manager向外传输的对象。

AO( Application Object):应用对象。 在Web层与Service层之间抽象的复用对象模型,极为贴近展示层,复用度不高。

POJO( Plain Ordinary Java Object):在本手册中, POJO专指只有setter/getter/toString的简单类,包括DO/DTO/BO/VO等。

Query:数据查询对象,各层接收上层的查询请求。 注意超过2个参数的查询封装,禁止使用Map类来传输。

说实话,术语太抽象,不利于理解,看完其实没解决啥疑惑,我会尽量用大白话(人话)来做解释,争取让大家都能看明白废话不多说,先来看张图,看完图估计大部分人就已经有了一个直观的感受了

img

面对这个图,让我们先从承上启下的 DTO 开始入手

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

这个传输通常指的前/后端之间的传输

DTO是一个比较特殊的对象,他有两种存在形式:

  • 在后端,他的存在形式是 java 对象,也就是在 controller 里面定义的那个东东,通常在后端不需要关心怎么从json转成java对象的,这个都是由一些成熟的框架帮你完成啦,比如spring框架
  • 在前端,他的存在形式通常是js里面的对象(也可以简单理解成json),也就是通过ajax请求的那个数据体

这也是为什么把他画成横跨两层的原因。这里可能会遇到个问题,现在微服务盛行,服务和服务之间调用的传输对象能叫DTO吗?我的理解是看情况。DTO本身的一个隐含的意义是要能够完整的表达一个业务模块的输出。如果服务和服务之间相对独立,那就可以叫DTO;如果服务和服务之间不独立,每个都不是一个完整的业务模块,拆开可能仅仅是因为计算复杂度或者性能的问题,那这就不能够叫做DTO,只能是BO。

VO(Value Object)值对象

VO就是展示用的数据,不管展示方式是网页,还是客户端,还是APP,只要是这个东西是让人看到的,这就叫VO。VO主要的存在形式就是js里面的对象(也可以简单理解成json)

VO和DTO的区别

主要有两个区别

  • 一个是字段不一样,VO根据需要会删减一些字段
  • 另一个是值不一样,VO会根据需要对DTO中的值进行展示业务的解释

举个简单的例子

DTO可能是这样的 {"gender":"男","age":35}

对于业务一来说只需要性别,而且因为是一个古风聊天室,也不能直接展示男,因此经过业务解释业务一的VO是{"gender":"公子"}

对于业务二来说只需要年龄,而且不需要精确的年龄,因此经过业务解释业务二的VO是

PO(Persistant Object)持久对象

PO比较好理解,简单说PO就是数据库中的记录,一个PO的数据结构对应着库中表的结构,表中的一条记录就是一个PO对象。通常PO里面除了get,set之外没有别的方法。对于PO来说,数量是相对固定的,一定不会超过数据库表的数量。PO 等同于 Entity,这俩概念是一致的。

BO(Business Object)业务对象

BO就是PO的组合。

简单的例子,比如说PO是一条交易记录,BO是一个人全部的交易记录集合对象。复杂点儿的例子PO1是交易记录,PO2是登录记录,PO3是商品浏览记录,PO4是添加购物车记录,PO5是搜索记录,BO是个人网站行为对象

BO是一个业务对象,一类业务就会对应一个BO,数量上没有限制,而且BO会有很多业务操作,也就是说除了get,set方法以外,BO会有很多针对自身数据进行计算的方法。为什么BO也画成横跨两层呢?原因是现在很多持久层框架自身就提供了数据组合的功能,因此BO有可能是在业务层由业务来拼装PO而成,也有可能是在数据库访问层由框架直接生成。

很多情况下为了追求查询的效率,框架跳过PO直接生成BO的情况非常普遍,PO只是用来增删改使用。

BO和DTO的区别

这两个的区别主要是就是字段的删减。BO对内,为了进行业务计算需要辅助数据,或者是一个业务有多个对外的接口,BO可能会含有很多接口对外所不需要的数据,因此DTO需要在BO的基础上,只要自己需要的数据,然后对外提供。在这个关系上,通常不会有数据内容的变化,内容变化要么在BO内部业务计算的时候完成,要么在解释VO的时候完成

DO

DO呢,标题不是还有个DO么?上面这些概念基本上已经涵盖了全部的流程,DO只是跟其中一个概念相同,但是跟哪个概念相同呢?

现在主要有两个版本

  • 一个是阿里巴巴的开发手册中的定义,DO( Data Object)这个等同于上面的PO
  • 另一个是在DDD(Domain-Driven Design)领域驱动设计中,由于领域驱动设计将业务逻辑层分解为应用层和领域层,业务对象在领域层中就变成了DO(Domain Object,领域对象)。不过,在领域驱动设计中,更准确的说法是领域模型对象。通常,领域模型对象包括实体、值对象、领域服务与领域事件。有时候,领域模型对象单指组成聚合的实体与值对象。宽泛地讲,只要表达了现实世界的领域概念,或者封装了领域行为逻辑,都可以认为是领域模型对象。一般而言,DO(Domain Object)这个等同于上面的BO。

总结

这几个概念很完整,我们在用的时候是必须按这个来做吗?当然不是的,系统和系统的复杂度不同,协作水平不同,完全没有必要教条主义,这些概念全上。上哪些概念,省哪些,我给一些实际建议

  1. PO这个没法省,不管叫PO还是Entity,怎么着都得有
  2. 一些工具类的系统和一些业务不是很复杂的系统DTO是可以和BO合并成一个,当业务扩展的时候注意拆分就行
  3. VO是可以第一个优化掉的,展示业务不复杂的可以压根儿不要,直接用DTO
  4. 这也是最重要的一条,概念是给人用的,多人协作的时候一定要保证大家的概念一致
posted @ 2021-09-27 10:59  Binge-和时间做朋友  阅读(633)  评论(0编辑  收藏  举报