关于各类O,DO/BO/DTO/VO/AO/PO

阿里巴巴Java开发手册

  • 连接:https://pan.baidu.com/s/11I9ViOrat-Bw_HA8yItXwA 密码:x5yi

2. DO/BO/DTO/VO/AO/PO

PO(persistant object) 持久对象

在 o/r 映射的时候出现的概念,若是没有 o/r 映射,没有这个概念存在了。一般对应数据模型 ( 数据库 ), 自己还有部分业务逻辑的处理。能够当作是与数据库中的表相映射的 java 对象。最简单的 PO 就是对应数据库中某个表中的一条记录,多个记录能够用 PO 的集合。 PO 中应该不包含任何对数据库的操做。html

DO(Domain Object)领域对象

就是从现实世界中抽象出来的有形或无形的业务实体。通常和数据中的表结构对应。前端

TO(Transfer Object) ,数据传输对象

在应用程序不一样 tie( 关系 ) 之间传输的对象java

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

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

VO(view object) 值对象

视图对象,用于展现层,它的做用是把某个指定页面(或组件)的全部数据封装起来。数据库

BO(business object) 业务对象

从业务模型的角度看 , 见 UML 元件领域模型中的领域对象。封装业务逻辑的 java 对象 , 经过调用 DAO 方法 , 结合 PO,VO 进行业务操做。 business object: 业务对象 主要做用是把业务逻辑封装为一个对象。这个对象能够包括一个或多个其它的对象。 好比一个简历,有教育经历、工做经历、社会关系等等。 咱们能够把教育经历对应一个 PO ,工做经历对应一个 PO ,社会关系对应一个 PO 。 创建一个对应简历的 BO 对象处理简历,每一个 BO 包含这些 PO 。 这样处理业务逻辑时,咱们就能够针对 BO 去处理。设计模式

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

纯的传统意义的 java 对象。就是说在一些 Object/Relation Mapping 工具中,可以作到维护数据库表记录的 persisent object 彻底是一个符合 Java Bean 规范的纯 Java 对象,没有增长别的属性和方法。个人理解就是最基本的 Java Bean ,只有属性字段及 setter 和 getter 方法!。浏览器

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

是一个 sun 的一个标准 j2ee 设计模式, 这个模式中有个接口就是 DAO ,它负持久层的操做。为业务层提供接口。此对象用于访问数据库。一般和 PO 结合使用, DAO 中包含了各类数据库的操做方法。经过它的方法 , 结合 PO 对数据库进行相关的操做。夹在业务逻辑与数据库资源中间。配合 VO, 提供数据库的 CRUD 操做网络

分层领域模型规约:session

  • DO( Data Object):与数据库表结构一一对应,经过DAO层向上传输数据源对象。
  • DTO( Data Transfer Object):数据传输对象,Service或Manager向外传输的对象。
  • BO( Business Object):业务对象。 由Service层输出的封装业务逻辑的对象。
  • AO( Application Object):应用对象。 在Web层与Service层之间抽象的复用对象模型,极为贴近展现层,复用度不高。
  • VO( View Object):显示层对象,一般是Web向模板渲染引擎层传输的对象。
  • POJO( Plain Ordinary Java Object):在本手册中, POJO专指只有setter/getter/toString的简单类,包括DO/DTO/BO/VO等。
  • Query:数据查询对象,各层接收上层的查询请求。 注意超过2个参数的查询封装,禁止使用Map类来传输。

领域模型命名规约:app

  • 数据对象:xxxDO,xxx即为数据表名。
  • 数据传输对象:xxxDTO,xxx为业务领域相关的名称。
  • 展现对象:xxxVO,xxx通常为网页名称。
  • POJO是DO/DTO/BO/VO的统称,禁止命名成xxxPOJO。

 

=====================

看了这么多,咱们可能仍是很懵,这么多内容,要记住是不可能的。必需要理解,多花些时间,彻底理解也是能够的,可是上面的内容比较绕脑。

总结一下:

DO 就是数据库的表。这个很简单。

PO是 ORM框架特有的,好比hibernate中的User类,User类可能有id、username、password等属性,另外User经过deptId关联部门表,在hibernate中,其表现就是一个 Dept 引用,而后经过hbm 配置一下,这样就关联了起来,另外User 可能还拥有数个联系方式,因此咱们经过一个 List 关联 Contact 类。User类本能够彻底的映射到 一个数据库的表,但如今 User类 并无直接 和 User表 一致, 看起来仍是有差异的。 因此这就是 PO。 若是是Mybatis呢? Mybatis虽然也是 ORM框架,但它明显不一样于hibernate,通常能够认为Mybatis的PO 就是 DO。

DTO 泛指用于展现层与服务层之间的数据传输对象,也就是 Controller层与 Service 层 传输用的, 也就是Service 层 接口的参数的类型。虽然能够理解,可是容易和VO 搞混,经常运用很差,DTO 的单向的? 仍是相互的?

VO 视图对象,用于展现层。 是前端(浏览器端)传给Controller层 的数据的类型, 也就是Controller层 接口的参数的类型。

BO 难以理解,理解了也很差运用。“封装业务逻辑的 java 对象 , 经过调用 DAO 方法 , 结合 PO,VO 进行业务操做”, 是否是能够认为 就是Service类? 不是的,但能够认为是Service类中用到的 封装了PO、VO 的类。—— 这样说,仍是懵逼。 实际上,我也没怎么见过。搞这么些纠缠不清的难概念,是要生生的把程序员玩残玩呆逼玩白发玩秃顶吗。

DAO 你们用得不少,不解释了。

TO、AO、POJO,通常不会使用。

Controller层 返回给前端的数据类型呢? 能够是VO、DTO

 

 ======================================

  • 用户发出请求(多是填写表单),表单的数据在展现层被匹配为VO。
  • 展现层把VO转换为服务层对应方法所要求的DTO,传送给服务层。
  • 服务层首先根据DTO的数据构造(或重建)一个DO,调用DO的业务方法完成具体业务。
  • 服务层把DO转换为持久层对应的PO(可使用ORM工具,也能够不用),调用持久层的持久化方法,把PO传递给它,完成持久化操做。
  • 对于一个逆向操做,如读取数据,也是用相似的方式转换和传递,略。

VO与DTO的区别

  你们可能会有个疑问(在笔者参与的项目中,不少程序员也有相同的疑惑):既然DTO是展现层与服务层之间传递数据的对象,为何还须要一个VO呢?对!对于绝大部分的应用场景来讲,DTO和VO的属性值基本是一致的,并且他们一般都是POJO,所以不必画蛇添足。但不要忘记这是实现层面的思惟,对于设计层面来讲,概念上仍是应该存在VO和DTO,由于二者有着本质的区别,DTO表明服务层须要接收的数据和返回的数据,而VO表明展现层须要显示的数据。

用一个例子来讲明可能会比较容易理解:例如服务层有一个getUser的方法返回一个系统用户,其中有一个属性是gender(性别),对于服务层来讲,它只从语义上定义:1-男性,2-女性,0-未指定,而对于展现层来讲,它可能须要用“帅哥”表明男性,用“美女”表明女性,用“秘密”表明未指定。说到这里,可能你还会反驳,在服务层直接就返回“帅哥美女”不就好了吗?对于大部分应用来讲,这不是问题,但设想一下,若是需求容许客户能够定制风格,而不一样风格对于“性别”的表现方式不同,又或者这个服务同时供多个客户端使用(不一样门户),而不一样的客户端对于表现层的要求有所不一样,那么,问题就来了。再者,回到设计层面上分析,从职责单一原则来看,服务层只负责业务,与具体的表现形式无关,所以,它返回的DTO,不该该出现与表现形式的耦合。

  理论归理论,这到底仍是分析设计层面的思惟,是否在实现层面必须这样作呢?一刀切的作法每每会得不偿失,下面我立刻会分析应用中如何作出正确的选择。

  VO与DTO的应用

  上面只是用了一个简单的例子来讲明VO与DTO在概念上的区别,本节将会告诉你如何在应用中作出正确的选择。

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

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

  如下场景须要优先考虑VO、DTO并存:

  • 上述场景的反面场景
  • 由于某种技术缘由,好比某个框架(如Flex)提供自动把POJO转换为UI中某些Field时,能够考虑在实现层面定义出VO,这个权衡彻底取决于使用框架的自动转换能力带来的开发和维护效率提高与设计多一个VO所多作的事情带来的开发和维护效率的降低之间的比对。
  • 若是页面出现一个“大视图”,而组成这个大视图的全部数据须要调用多个服务,返回多个DTO来组装(固然,这一样能够经过服务层提供一次性返回一个大视图的DTO来取代,但在服务层提供一个这样的方法是否合适,须要在设计层面进行权衡)。

  DTO与DO的区别

  首先是概念上的区别,DTO是展现层和服务层之间的数据传输对象(能够认为是二者之间的协议),而DO是对现实世界各类业务角色的抽象,这就引出了二者在数据上的区别,例如UserInfo和User(对于DTO和DO的命名规则,请参见笔者前面的一篇博文),对于一个getUser方法来讲,本质上它永远不该该返回用户的密码,所以UserInfo至少比User少一个password的数据。而在领域驱动设计中,正如第一篇系列文章所说,DO不是简单的POJO,它具备领域业务逻辑。

  DTO与DO的应用

  从上一节的例子中,细心的读者可能会发现问题:既然getUser方法返回的UserInfo不该该包含password,那么就不该该存在password这个属性定义,但若是同时有一个createUser的方法,传入的UserInfo须要包含用户的password,怎么办?在设计层面,展现层向服务层传递的DTO与服务层返回给展现层的DTO在概念上是不一样的,但在实现层面,咱们一般不多会这样作(定义两个UserInfo,甚至更多),由于这样作并不见得很明智,咱们彻底能够设计一个彻底兼容的DTO,在服务层接收数据的时候,不应由展现层设置的属性(如订单的总价应该由其单价、数量、折扣等决定),不管展现层是否设置,服务层都一律忽略,而在服务层返回数据时,不应返回的数据(如用户密码),就不设置对应的属性。

  对于DO来讲,还有一点须要说明:为何不在服务层中直接返回DO呢?这样能够省去DTO的编码和转换工做,缘由以下:

  • 二者在本质上的区别可能致使彼此并不一一对应,一个DTO可能对应多个DO,反之亦然,甚至二者存在多对多的关系。
  • DO具备一些不该该让展现层知道的数据
  • DO具备业务方法,若是直接把DO传递给展现层,展现层的代码就能够绕过服务层直接调用它不该该访问的操做,对于基于AOP拦截服务层来进行访问控制的机制来讲,这问题尤其突出,而在展现层调用DO的业务方法也会由于事务的问题,让事务难以控制。
  • 对于某些ORM框架(如Hibernate)来讲,一般会使用“延迟加载”技术,若是直接把DO暴露给展现层,对于大部分状况,展现层不在事务范围以内(Open session in view在大部分状况下不是一种值得推崇的设计),若是其尝试在Session关闭的状况下获取一个未加载的关联对象,会出现运行时异常(对于Hibernate来讲,就是LazyInitiliaztionException)。
  • 从设计层面来讲,展现层依赖于服务层,服务层依赖于领域层,若是把DO暴露出去,就会致使展现层直接依赖于领域层,这虽然依然是单向依赖,但这种跨层依赖会致使没必要要的耦合。

  对于DTO来讲,也有一点必须进行说明,就是DTO应该是一个“扁平的二维对象”,举个例子来讲明:若是User会关联若干个其余实体(例如Address、Account、Region等),那么getUser()返回的UserInfo,是否就须要把其关联的对象的DTO都一并返回呢?若是这样的话,必然致使数据传输量的大增,对于分布式应用来讲,因为涉及数据在网络上的传输、序列化和反序列化,这种设计更不可接受。若是getUser除了要返回User的基本信息外,还须要返回一个AccountId、AccountName、RegionId、RegionName,那么,请把这些属性定义到UserInfo中,把一个“立体”的对象树“压扁”成一个“扁平的二维对象”。笔者目前参与的项目是一个分布式系统,该系统无论三七二十一,把一个对象的全部关联对象都转换为相同结构的DTO对象树并返回,致使性能很是的慢。

  DO与PO的区别

  DO和PO在绝大部分状况下是一一对应的,PO是只含有get/set方法的POJO,但某些场景仍是能反映出二者在概念上存在本质的区别:

  • DO在某些场景下不须要进行显式的持久化,例如利用策略模式设计的商品折扣策略,会衍生出折扣策略的接口和不一样折扣策略实现类,这些折扣策略实现类能够算是DO,但它们只驻留在静态内存,不须要持久化到持久层,所以,这类DO是不存在对应的PO的。
  • 一样的道理,某些场景下,PO也没有对应的DO,例如老师Teacher和学生Student存在多对多的关系,在关系数据库中,这种关系须要表现为一个中间表,也就对应有一个TeacherAndStudentPO的PO,但这个PO在业务领域没有任何现实的意义,它彻底不能与任何DO对应上。这里要特别声明,并非全部多对多关系都没有业务含义,这跟具体业务场景有关,例如:两个PO之间的关系会影响具体业务,而且这种关系存在多种类型,那么这种多对多关系也应该表现为一个DO,又如:“角色”与“资源”之间存在多对多关系,而这种关系很明显会表现为一个DO——“权限”。
  • 某些状况下,为了某种持久化策略或者性能的考虑,一个PO可能对应多个DO,反之亦然。例如客户Customer有其联系信息Contacts,这里是两个一对一关系的DO,但可能出于性能的考虑(极端状况,权做举例),为了减小数据库的链接查询操做,把Customer和Contacts两个DO数据合并到一张数据表中。反过来,若是一本图书Book,有一个属性是封面cover,但该属性是一副图片的二进制数据,而某些查询操做不但愿把cover一并加载,从而减轻磁盘IO开销,同时假设ORM框架不支持属性级别的延迟加载,那么就须要考虑把cover独立到一张数据表中去,这样就造成一个DO对应多个PO的状况。
  • PO的某些属性值对于DO没有任何意义,这些属性值多是为了解决某些持久化策略而存在的数据,例如为了实现“乐观锁”,PO存在一个version的属性,这个version对于DO来讲是没有任何业务意义的,它不该该在DO中存在。同理,DO中也可能存在不须要持久化的属性。

  DO与PO的应用

  因为ORM框架的功能很是强大而大行其道,并且JavaEE也推出了JPA规范,如今的业务应用开发,基本上不须要区分DO与PO,PO彻底能够经过JPA,Hibernate Annotations/hbm隐藏在DO之中。虽然如此,但有些问题咱们还必须注意:

  • 对于DO中不须要持久化的属性,须要经过ORM显式的声明,如:在JPA中,能够利用@Transient声明。
  • 对于PO中为了某种持久化策略而存在的属性,例如version,因为DO、PO合并了,必须在DO中声明,但因为这个属性对DO是没有任何业务意义的,须要让该属性对外隐藏起来,最多见的作法是把该属性的get/set方法私有化,甚至不提供get/set方法。但对于Hibernate来讲,这须要特别注意,因为Hibernate从数据库读取数据转换为DO时,是利用反射机制先调用DO的空参数构造函数构造DO实例,而后再利用JavaBean的规范反射出set方法来为每一个属性设值,若是不显式声明set方法,或把set方法设置为private,都会致使Hibernate没法初始化DO,从而出现运行时异常,可行的作法是把属性的set方法设置为protected。
  • 对于一个DO对应多个PO,或者一个PO对应多个DO的场景,以及属性级别的延迟加载,Hibernate都提供了很好的支持,请参考Hibnate的相关资料。

  到目前为止,相信你们都已经比较清晰的了解VO、DTO、DO、PO的概念、区别和实际应用了。经过上面的详细分析,咱们还能够总结出一个原则:分析设计层面和实现层面彻底是两个独立的层面,即便实现层面经过某种技术手段能够把两个彻底独立的概念合二为一,在分析设计层面,咱们仍然(至少在头脑中)须要把概念上独立的东西清晰的区分开来,这个原则对于作好分析设计很是重要(工具越先进,每每会让咱们越麻木)。第一篇系列博文抛砖引玉,大唱领域驱动设计的优点,但其实领域驱动设计在现实环境中仍是有种种的限制,须要选择性的使用,正如我在《田七的智慧》博文中提到,咱们不能永远的理想化的去选择所谓“最好的设计”,在必要的状况下,咱们仍是要勇于放弃,由于最合适的设计才是最好的设计。原本,系列中的第二篇博文应该是讨论领取驱动设计的限制和如何选择性的使用,但请原谅个人疏忽,下一篇系列博文会把这个主题补上,敬请关注。

 

=======================================

bo dto vo po有必要划分这么清楚吗

咱们作各类分层,而后呢,为每一层与其余层的有向传输的数据 分别命名,这样,咱们就产生了不少的XxxO,

前端到Controller的能够命名一个VO,

Controller到Service的能够命名一个DTO,

Service到DAO的能够命名一个PO,

DAO返回给Service的能够命名一个DO,

Service到Controller的能够命名一个BO,

Service到前端的能够命名一个XxO,

理论上这样固然是能够的,可是,若是 VO、DTO、PO、DO、BO、XxO 的字段基本是同样的, 这样作太死板了~!

 

不可缺乏的显然是DO,有时候,咱们可能会看到一些不规范的命名,好比model层,XxxModel,XxxEntity, 其实就是DO。

我以前看到有的项目,所有的传输参数类型基本都是 DO,根本不须要其余的O,省去了 O们之间相互转化的麻烦,大大提升了 代码的可读性。

虽然如此,咱们不能一刀切,简单的项目,所有都共用一个DO,也问题不大,可是若是大项目,须要考虑 良好的设计, 那么增长一个VO、DTO 也不是不能够的。转化起来虽然有些麻烦,可是各O的含义是明确的。

 

因此呢? 仍是按状况来。我就是一直很是反感那种动不动一个XxO的人,看到那些丑陋的 O之间转换的代码,严重影响了可读性和美观。我建议不要太多O,通常使用DTO、DO 就能够了。DTO定义在Controller层,DO定义在DAO层

 

大部分转载至:

https://www.cnblogs.com/tsiangleo/p/4550355.html

http://www.blogjava.net/johnnylzb/archive/2010/05/27/321968.html

相关文章
相关标签/搜索