概念

POJO(plain ordinary java object)

无规则简单java对象

VO(View Object)

视图对象,用于表现层,它的作用是把某个指定页面(或组件)的所有数据封装起来。
VO通常是 Web 向模板渲染引擎层传输的对象。

对应页面显示(web页面/swt、swing界面)的数据对象。
可以和表对应,也可以不,这根据业务的需要。

DTO/TO(Data Transfer Object)

数据传输对象:用于表现层与服务层之间的数据传输对象,它不应该包含业务逻辑。
DTO可以是Service 和 Manager向外传输的对象。
大多数情况下,DTO内的数据来自多个表。
比如一张表有100个字段,那么对应的PO就有100个属性。但view层只需显示10个字段,没有必要把整个PO对象传递到客户端,这时我们就可以用只有这10个属性的DTO来传输数据到客户端。到达客户端以后,如果用这个对象来对应界面显示,那此时它的身份就转为VO。

DO(Domain Object)

领域对象:从现实世界中抽象出来的有形或无形的业务实体。
在领域驱动设计中,DO不是简单的POJO,它具有领域业务逻辑。

BO(business object )

业务对象,封装业务逻辑后的对象。
处理业务逻辑时,我们可以针对BO去处理。
BO可以是由 Service 层输出的封装业务逻辑的对象。
业务对象主要作用是把业务逻辑封装为一个对象。这个对象可以包括一个或多个其它的对象。
比如一个简历,有教育经历、工作经历、培训经历等等。我们可以把教育经历对应一个PO,工作经历对应一个PO,培训经历对应一个PO。建立一个对应简历的BO对象处理简历,每个BO包含这些PO。

BO可以包括多个PO,通常需要将BO转化成PO,才能进行数据的持久化,反之,从DB中得到的PO,需要转化成BO才能在业务层使用)。

PO(Persistent Object)

持久化对象,它跟持久层(通常是关系型数据库)的数据结构形成一一对应的映射关系。
PO是只含有get/set方法的POJO
如果持久层是关系型数据库,那么,对应数据库表中的实体,可以简单认为一个PO对应数据库中的一条记录,数据表中的每个字段(或若干个)对应PO的一个(或若干个)属性。
PO有时也被称为Data对象,PO中不应包含任何对数据库的操作。

QUERY

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

区分

图示

以一个时序图建立简单模型来描述上述对象在三层架构应用中的位置:

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

命名

  • 数据传输对象DTO,建议用“**Info”,如:CustomerInfo
  • 领域对象DO本身就是业务的核心,建议以真实名称出现,比如:Account、Customer

详解

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?回到设计层面,服务层的职责依然不应该与表现层耦合,所以,DTO对于“性别”来说,依然不能用“帅哥美女”,这个转换应该依赖于页面的脚本(如JavaScript)或其他机制(JSTL、EL、CSS)。
  • 即使客户端可以进行定制,或者存在多个不同的客户端,如果客户端能够用某种技术(脚本或其他机制)实现转换,同样可以让VO退隐。

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

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

DTO与DO

区别

-概念上的区别:DTO是表现层和服务层之间的数据传输对象(可以认为是两者之间的协议),而DO是对现实世界各种业务角色的抽象。

  • 数据上的区别:例如UserInfo和User,对于一个getUser()方法来说,本质上它永远不应该返回用户的密码,因此UserInfo至少比User少一个password的数据。

应用

比如:getUser()方法返回的UserInfo不应该包含password,那么就不应该存在password这个属性定义,但如果同时有一个createUser()方法,传入的UserInfo需要包含用户的password。

在设计层面,表现层向服务层传递的DTO与服务层返回给表现层的DTO在概念上是不同的,但在实现层面,我们通常很少会这样做(定义两个UserInfo,甚至更多),因为这样做并不见得很明智。我们可以设计一个完全兼容的DTO:在服务层接收数据的时候,不该由表现层设置的属性(如订单的总价应该由其单价、数量、折扣等决定),无论表现层是否设置,服务层都一概忽略,而在服务层返回数据时,不该返回的数据(如用户密码),就不设置对应的属性。

之所以不在服务层中直接返回DO的原因是:

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

DTO应该是一个“扁平的二维对象”,比如:如果User会关联若干个其他实体(例如Address、Account、Region等),那么getUser()返回的UserInfo,是否就需要把其关联的对象的DTO都一并返回呢?如果这样的话,必然导致数据传输量的大增,对于分布式应用来说,由于涉及数据在网络上的传输、序列化和反序列化,这种设计更不可接受。如果getUser除了要返回User的基本信息外,还需要返回一个AccountId、AccountName、RegionId、RegionName,那么,请把这些属性定义到UserInfo中,把一个“立体”的对象树“压扁”成一个“扁平的二维对象”。

DO与PO

区别

DO和PO在绝大部分情况下是一一对应的,但某些场景还是能反映出两者在概念上存在本质的区别:

  • 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中也可能存在不需要持久化的属性。

应用

由于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的相关资料。

PO,BO,VO,DTO和POJO相关推荐

  1. PO,BO,VO,DTO和POJO的概念区分

    PO,BO,VO,DTO和POJO的概念区分 文章目录 PO,BO,VO,DTO和POJO的概念区分 POJO(plain ordinary java object) VO(View Object) ...

  2. Java各种对象(PO,BO,VO,DTO,POJO,DAO,Entity,JavaBean,JavaBeans)的区分

    Java各种对象(PO,BO,VO,DTO,POJO,DAO,Entity,JavaBean,JavaBeans)的区分 PO:持久对象 (persistent object),po(persiste ...

  3. PO/BO/VO/DTO/POJO/DAO/DO

    文章目录 DO(Domain Object) DO(Data Object) PO VO BO DTO POJO DAO JavaBean EJB Entity 应用程序的分层设计 MVC 业务分层 ...

  4. java中bean对象_JAVA中PO,BO,VO,DTO,POJO,Entity,JavaBean,JavaBeans各个对象的区别,以及lombo、jpa简介及用法...

    常见JAVA类概念介绍 PO:持久对象 (persistent object). 是ORM(Objevt Relational Mapping)框架中Entity,PO属性和数据库中表的字段形成一一对 ...

  5. PO BO VO DTO POJO DAO DO 在java中的概念

    PO BO DTO VO POJO PO DTO VO BO 都叫POJO,就是个简单的java对象: DAO 是进行数据库增删改查的类. BO 业务对象,封装对象.复杂对象 ,里面可能包含多个类: ...

  6. PO BO VO DTO POJO DAO概念

    刚开始写blog,主要的目的是积累,学习,供日后查找! 如题,今天跟主管交流,被好多名词整蒙了,这些词以前都听说过,但是对其内在的含义并不是很清楚的了解,借此机会写上来,增加记忆和理解吧. 一下是原文 ...

  7. PO,BO,VO,DTO区别

    PO(bean.entity等命名): 持久对象,对应数据库表中的每一行记录,对应数据库的entity BO(service.manager.business等命名) 业务对象,将业务逻辑封装成一个对 ...

  8. PO BO VO DTO POJO DAO概念及其作用(附转换图)

    J2EE开发中大量的专业缩略语很是让人迷惑,尤其是跟一些高手讨论问题的时候,三分钟就被人家满口的专业术语喷晕了,PO VO BO DTO POJO DAO,一大堆的就来了(听过老罗对这种现象的批判的朋 ...

  9. java常见业务对象_Java各种对象(PO,BO,VO,DTO,POJO,DAO,Entity,JavaBean,JavaBeans)的区分...

    PO:持久对象 (persistent object),po(persistent object)就是在Object/Relation Mapping框架中的Entity,po的每个属性基本上都对应数 ...

最新文章

  1. java 宽字节_宽字节注入
  2. unity test相关
  3. SAP MIGO收货界面'批次'分类选项卡里不出现'分类'按钮之对策
  4. Cerebras发布全球首个人类大脑规模的AI解决方案
  5. 硬件安全(二) 5G时代IOT环境下芯片安全风险与挑战
  6. apache isis_使用Apache Isis快速进行SEMAT应用程序开发
  7. 【STM32】IIC的基本原理(实例:普通IO口模拟IIC时序读取24C02)(转载)
  8. 北京Php月收入2w,给你北京户口,前提要辞掉月薪2w的工作,在月薪5千左右的岗位干10年,你干吗?...
  9. android google map 标记,android google map添加标记和TipView
  10. JS - this,call,apply
  11. python的numpy库中的where_关于numpy.where()函数 返回值的解释
  12. [知识竞赛策划方案][图]何用PPT制作知识竞赛所需要的题库?作为一个普通的单位,由于不具备电视台专用的比赛平台,如果要搞一场极致专业的知识竞赛?同时花钱最少?
  13. RuntimeError:The size of tensor a (100) must match the size of tensor b (12800) at non-singleton di
  14. 有卡却显示无服务器,为什么卡一直显示无服务
  15. cython代码编译和setup.py文件编写
  16. IOS锁屏状态播放音乐时显示专辑信息和图片
  17. 烽火狼烟丨Fastjson反序列化漏洞风险提示
  18. 手码万字-带你全面了解存储基础知识
  19. html 语言注释,HTML 注释
  20. python爬虫能赚钱吗-个人利用Python爬虫技术怎么挣钱-10万被动收入

热门文章

  1. Ubuntu16.04源码编译安装开源版的迅雷Xware Desktop
  2. 10、kanzi入门——Hello World与Kanzi Engine API设置属性
  3. 如何制作翻页的电子书?
  4. optimizing java_书山天道 - Optimizing Java
  5. 王道考研数据结构笔记之基本概念
  6. vs2019编译zlib全过程
  7. 软件版本alpha、Beta、RC、GA、DMR等含义
  8. 用 Microsoft.mshtml.dll 和 WebClient 自己实现网页保存为 MHT 文件
  9. rust服务器配置文件,使用Rust编写一个简单的Socket服务器(1):Rust下的配置载入...
  10. mysql字符集maxlen_Mysql_字符集设置