浅析VO、DTO、DO、PO、POJO区别

传统规范图

浅析VO、DTO、DO、PO、POJO区别_第1张图片

另一种规范图

浅析VO、DTO、DO、PO、POJO区别_第2张图片

整体流程
  1. 用户发出请求(可能是填写表单),表单的数据在展示层被匹配为VO。
  2. 展示层把VO转换为服务层对应方法所要求的DTO,传送给服务层。
  3. 服务层首先根据DTO的数据构造(或重建)一个DO,调用DO的业务方法完成具体业务。
  4. 服务层把DO转换为持久层对应的PO(可以使用ORM工具,也可以不用),调用持久层的持久化方法,把PO传递给它,完成持久化操作。
  5. 对于一个逆向操作,如读取数据,也是用类似的方式转换和传递,略。
VO(Value Object)值对象

视图对象,用于展示层,它的作用是把某个指定页面(或组件)的所有数据封装起来。VO就是展示用的数据,不管展示方式是网页,还是客户端,还是APP,只要是这个东西是让人看到的,这就叫VO。

VO通常用于前端和服务端Controller交互。

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

数据传输对象,这个概念来源于J2EE的设计模式,原来的目的是为了EJB的分布式应用提供粗粒度的数据实体,以减少分布式调用的次数,从而提高分布式调用的性能和降低网络负载,但在这里,我泛指用于展示层与服务层之间的数据传输对象。

DTO通常用于Controller和Service交互。

BO(business object) 业务对象

业务层对象,是简单的真实世界的软件抽象,通常位于中间层。BO 的主要作用是把业务逻辑封装为一个对象,这个对象可以包括一个或多个其它的对象。也有认为BO就是PO的组合。

PO(Persistent Object)持久化对象

持久化对象,它跟持久层(通常是关系型数据库)的数据结构形成一一对应的映射关系,如果持久层是关系型数据库,那么,数据表中的每个字段(或若干个)就对应PO的一个(或若干个)属性。

PO就是数据库中的记录,一个PO的数据结构对应着库中表的结构,表中的一条记录就是一个PO对象
通常PO里面除了get,set之外没有别的方法。对于PO来说,数量是相对固定的,一定不会超过数据库表的数量

DO(Domain Object)领域对象

上面这些概念基本上已经涵盖了全部的流程,DO只是跟其中一个概念相同,但是跟哪个概念相同呢?
现在主要有两个版本:

  1. 阿里巴巴的开发手册中的定义:DO( Data Object)这个等同于下面的PO

  2. 在DDD(Domain-Driven Design)领域驱动设计中,DO(Domain Object)这个等同于上面的BO

DAO(data access object) 数据访问对象

DAO(Data Access Object)数据访问对象,它是一个面向对象的数据库接口,负责持久层的操作,为业务层提供接口,主要用来封装对数据库的访问,常见操作无外乎 CURD。我们也可以认为一个 DAO 对应一个 POJO 的对象,它位于业务逻辑与数据库资源中间,可以结合 PO 对数据库进行相关的操作。

POJO(plain ordinary java object) 简单无规则 java 对象

纯的传统意义的 java 对象。就是说在一些 Object/Relation Mapping 工具中,能够做到维护数据库表记录的 persisent object 完全是一个符合 Java Bean 规范的纯 Java 对象,没有增加别的属性和方法。我的理解就是最基本的 Java Bean ,只有属性字段及 setter 和 getter 方法!。

POJO 可认为是 DO/DTO/BO/VO 的统称,禁止命名成 xxxPOJO。

VO和DTO的区别

主要有两个区别

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

大家可能会有个疑问:既然DTO是展示层与服务层之间传递数据的对象,为什么还需要一个VO呢?
对于绝大部分的应用场景来说,DTO和VO的属性值基本是一致的,而且他们通常都是POJO,因此没必要多此一举,但不要忘记这是实现层面的思维,对于设计层面来说,概念上还是应该存在VO和DTO,因为两者有着本质的区别,DTO代表服务层需要接收的数据和返回的数据,而VO代表展示层需要显示的数据。

在以下才场景中,我们可以考虑把VO与DTO二合为一(注意:是实现层面):

  1. 当需求非常清晰稳定,而且客户端很明确只有一个的时候,没有必要把VO和DTO区分开来,这时候VO可以退隐,用一个DTO即可,为什么是VO退隐而不是DTO?回到设计层面,服务层的职责依然不应该与展示层耦合,所以,对于前面的例子,你很容易理解,DTO对于“性别”来说,依然不能用“帅哥美女”,这个转换应该依赖于页面的脚本(如JavaScript)或其他机制(JSTL、EL、CSS)。
  2. 即使客户端可以进行定制,或者存在多个不同的客户端,如果客户端能够用某种技术(脚本或其他机制)实现转换,同样可以让VO退隐。

以下场景需要优先考虑VO、DTO并存:

  1. 上述场景的反面场景。
  2. 因为某种技术原因,比如某个框架(如Flex)提供自动把POJO转换为UI中某些Field时,可以考虑在实现层面定义出VO,这个权衡完全取决于使用框架的自动转换能力带来的开发和维护效率提升与设计多一个VO所多做的事情带来的开发和维护效率的下降之间的比对。
  3. 如果页面出现一个“大视图”,而组成这个大视图的所有数据需要调用多个服务,返回多个DTO来组装(当然,这同样可以通过服务层提供一次性返回一个大视图的DTO来取代,但在服务层提供一个这样的方法是否合适,需要在设计层面进行权衡)。
BO和DTO的区别

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

这两个的区别主要是就是字段的删减。

最后总结与实际应用

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

  1. PO这个没法省,不管叫PO还是Entity,怎么着都得有
  2. 一些工具类的系统和一些业务不是很复杂的系统DTO是可以和BO合并成一个,当业务扩展的时候注意拆分就行
  3. VO是可以第一个优化掉的,展示业务不复杂的可以压根儿不要,直接用DTO
  4. 这也是最重要的一条,概念是给人用的,多人协作的时候一定要保证大家的概念一致

我们可以总结出一个原则:分析设计层面和实现层面完全是两个独立的层面,即使实现层面通过某种技术手段可以把两个完全独立的概念合二为一,在分析设计层面,我们仍然(至少在头脑中)需要把概念上独立的东西清晰的区分开来,这个原则对于做好分析设计非常重要(工具越先进,往往会让我们越麻木)。

本文参考文章:
浅析VO、DTO、DO、PO的概念、区别和用处
JavaWeb - 我们的开发规范(VO、DTO、BO、PO、DO、POJO)

你可能感兴趣的:(java)