领域驱动模型VO、DTO、DO、PO有什么区别

发布时间:2021-10-18 10:46:05 作者:小新
来源:亿速云 阅读:204

这篇文章主要为大家展示了“领域驱动模型VO、DTO、DO、PO有什么区别”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“领域驱动模型VO、DTO、DO、PO有什么区别”这篇文章吧。

领域模型中的实体类

领域模型中的实体类分为四种模型:VO、DTO、DO、PO,各种实体类用于不同业务层次间的交互,并会在层次内实现实体类之间的转化。

业务分层为:视图层(VIEW+ACTION)、服务层(SERVICE)、持久层(DAO),相应各层间实体的传递如下:

领域驱动模型VO、DTO、DO、PO有什么区别

VO (View Object)视图对象

用于展示层,它的作用是把某个指定页面(或组件)的所有数据封装起来。

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

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

比如一张表有100个字段,那么对应的DTO就有100个属性(大多数情况下,DTO内的数据来自多张表)。但是view层只需要显示10个字段,没有必要把整个PO对象传递到  client,这时我们就可以用只有这10个属性的DTO来传输数据到 client,这样也不会暴露 server  端的表结构。到达客户端后,如果用这个对象来对应界面展示,那么此时它的身份就转为 VO。

DO(Domain Object)领域对象

就是从现实世界中抽象出来的有形或无形的业务实体。

PO(Persistent Object):持久化对象

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

对于以上概念的理解,可能还不能形成一种抽象化思维,我们通过一个时序图建立模型来描述上述对象在三层架构应用中的位置:

领域驱动模型VO、DTO、DO、PO有什么区别

对于一个逆向操作,如读取数据,也是用类似的方式转换和传递。

VO 与 DTO 对比

VO 与 DTO 的区别

在这里我们可能会问:既然 DTO 是展示层与服务层之间传递数据的对象,为什么还要一个 VO 呢?

是的,对于绝大部分的应用场景来说,DTO 和 VO 的属性值基本是一致的,而且他们通常都是  POJO,因此没必要多此一举。但不要忘记这是实现层的思维,对于设计层面来说,概念上还是应该存在 VO 和 DTO,因此两者有着本质的区别,DTO  代表服务层需要接收的数据和返回的数据,而 VO 代表展示层需要显示的数据。

用一个例子来说明可能会比较容易理解:

例如:Service 层有一个 getUser 的方法返回一个系统用户,其中有一个属性是 gender(性别),对于 Service  层来说,它只从语义上定义:1-男性、2-女性、0-未指定,而对于展示层来说,它可能需要用“帅哥”代表男性、“美女”代表女性、“秘密”代表未指定。

说到这里,可能你还会反驳,在服务层直接返回“帅哥、美女”不就行吗?对于大部分应用来说,这不是问题,但设想以下,如果需求允许客户可以定制风格,而不同的客户端对于表现层的要求有所不同,那么,问题就来了。再者,回到设计层面分析,从职责单一原则来看,服务层只负责业务,与具体的表现形式无关,因此,它返回的  DTO,不应该出现与表现形式的耦合。

理论归理论,这到底还是分析设计层面的思维,是否在具体实现层面必须这样做呢?一刀切的做法往往会得不偿失,下面我们具体分析应用中如何做出正确的选择。

VO 与 DTO 的应用

在上面只是用了一个简单的例子来说 VO 与 DTO 在概念上区别,这里我们具体分析在应用中如何做出正确的选择。

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

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

DTO 与 DO 对比

DTO 与 DO 的区别

首先是概念上的区别,DTO 是展示层和服务层之间的数据传输对象(可以认为是两者之间的协议),而 DO  是对现实世界各种业务角色的抽象,这就引出了两者在数据上的区别。

例如:UserInfo 和 User ,对于一个 getUser 方法来说,本质上它永远不应该返回用户的密码,因此 UserInfo 至少比 User  少一个 password 的数据。而在领域驱动设计中,DO不是简单的POJO,它具有领域业务逻辑。

DTO 与 DO 的应用

从上面会反向问题:既然 getUser 方法返回的 UserInfo 不应该包含 password,那么就不应该存在 password  这个属性定义,但是如果同时有一个 createUser 的防腐,传入的UserInfo需要包含用户的 password,怎么办?

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

对于DO来说,还有一点需要说明:为什么不在服务层中直接返回 DO 呢?这样可以省去 DTO 的编码和转换工作,原因如下:

对于DTO来说,也有一点必须进行说明,就是DTO应该是一个“扁平的二维对象”举个例子:

DO 与 PO 对比

DO 与 PO 的区别

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

这里要特别声明,并不是所有多对多关系都没有业务含义,这跟具体业务场景有关,例如:两个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之中。虽然如此,但有些问题我们还必须注意:

以上是“领域驱动模型VO、DTO、DO、PO有什么区别”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

推荐阅读:
  1. 一遍文章搞清楚VO、DTO、DO、PO的概念、区别
  2. entity、bo、vo、po、dto、pojo如何理解和区分?

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

上一篇:php中函数禁用绕过的原理与用法

下一篇:如何使用分布式定时任务

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》