最近爆火的DDD到底是什么?一文带你落地DDD

最近爆火的DDD到底是什么?一文带你落地DDD这篇博客详细介绍了 DDD 领域驱动设计 的核心概念 包括防腐层 实体 值对象 聚合 聚合根 领域服务 应用服务 工厂 资源库 事件模型等 并探讨了 DDD 的架构设计 如严格分层架构 松散分层架构

大家好,欢迎来到IT知识分享网。

2.3.2.上下文组织和集成模式

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

防腐层(Anticorruption Layer):简称ACL,在集成两个上下文,如果两边都状态良好,可以引入防腐层来作为两边的翻译,并且可以隔离两边的领域模型。

最近爆火的DDD到底是什么?一文带你落地DDD

2.3.3.实体

========

DDD中要求实体是唯一的且可持续变化的。意思是说在实体的生命周期内,无论其如何变化,其仍旧是同一个实体。唯一性由唯一的身份标识来决定的。可变性也正反映了实体本身的状态和行为。

实体 = 唯一身份标识 + 可变性【状态 + 行为】

2.3.4.值对象

=========

当你只关心某个对象的属性时,该对象便可作为一个值对象。 我们需要将值对象看成不变对象,不要给它任何身份标识,还应该尽量避免像实体对象一样的复杂性。

值对象=将一个值用对象的方式进行表述,来表达一个具体的固定不变的概念。

2.3.5.聚合

========

聚合是领域对象的显式分组,旨在支持领域模型的行为和不变性,同时充当一致性和事务性边界。

我们把一些关联性极强、生命周期一致的实体、值对象放到一个聚合里。

2.3.6.聚合根

=========

聚合的根实体,最具代表性的实体

2.3.7.领域服务

==========

当一些逻辑不属于某个实体时,可以把这些逻辑单独拿出来放到领域服务中 理想的情况是没有领域服务,如果领域服务使用不恰当慢慢又演化回了以前逻辑都在service层的局面。

可以使用领域服务的情况:

  • 执行一个显著的业务操作
  • 对领域对象进行转换
  • 以多个领域对象作为输入参数进行计算,结果产生一个值对象

2.3.8.应用服务

==========

是聚合的管理,仓储介于领域模型和数据模型之间,主要用于聚合的持久化和检索。它隔离了领域模型和数据模型,以便我们关注于领域模型而不需要考虑如何进行持久化。

我们将暂时不使用的领域对象从内存中持久化存储到磁盘中。当日后需要再次使用这个领域对象时,根据 key 值到数据库查找到这条记录,然后将其恢复成领域对象,应用程序就可以继续使用它了,这就是领域对象持久化存储的设计思想

2.3.9.工厂

========

职责是创建完整的聚合

  • 工厂方法
  • 工厂类

领域模型中的工厂

  • 将创建复杂对象和聚合的职责分配给一个单独的对象,它并不承担领域模型中的职责,但是领域设计的一部份
  • 对于聚合来说,我们应该一次性的创建整个聚合,并且确保它的不变条件得到满足
  • 工厂只承担创建模型的工作,不具有其它领域行为
  • 一个含有工厂方法的聚合根的主要职责是完成它的聚合行为
  • 在聚合上使用工厂方法能更好的表达通用语言,这是使用构造函数所不能表达的

聚合根中的工厂方法

  • 聚合根中的工厂方法表现出了领域概念
  • 工厂方法可以提供守卫措施

领域服务中的工厂

  • 在集成限界上下文时,领域服务作为工厂
  • 领域服务的接口放在领域模型内,实现放在基础设施层

2.3.10.资源库【仓储】

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

是聚合的管理,仓储介于领域模型和数据模型之间,主要用于聚合的持久化和检索。它隔离了领域模型和数据模型,以便我们关注于领域模型而不需要考虑如何进行持久化。

我们将暂时不使用的领域对象从内存中持久化存储到磁盘中。当日后需要再次使用这个领域对象时,根据 key 值到数据库查找到这条记录,然后将其恢复成领域对象,应用程序就可以继续使用它了,这就是领域对象持久化存储的设计思想

2.3.11.事件模型

===========

领域事件是一个领域模型中极其重要的部分,用来表示领域中发生的事件。忽略不相关的领域活动,同时明确领域专家要跟踪或希望被通知的事情,或与其他模型对象中的状态更改相关联

领域事件 = 事件发布 + 事件存储 + 事件分发 + 事件处理。

比如下订单后,给用户增长积分与赠送优惠券的需求。如果使用瀑布流的方式写代码。一个个逻辑调用,那么不同用户,赠送的东西不同,逻辑就会变得又臭又长。这里的比较好的方式是,用户下订单成功后,发布领域事件,积分聚合与优惠券聚合监听订单发布的领域事件进行处理。

2.4.DDD架构总览

===========

2.4.1.架构图

=========

严格分层架构:某层只能与直接位于的下层发生耦合。

松散分层架构:允许上层与任意下层发生耦合

依赖倒置原则

高层模块不应该依赖于底层模块,两者都应该依赖于抽象

抽象不应该依赖于实现细节,实现细节应该依赖于接口

简单的说就是面向接口编程。

按照DIP的原则,领域层就可以不再依赖于基础设施层,基础设施层通过注入持久化的实现就完成了对领域层的解耦,采用依赖注入原则的新分层架构模型就变成如下所示:

最近爆火的DDD到底是什么?一文带你落地DDD

从上往下

第一层为用户交互层,web请求,rpc请求,mq消息等外部输入均被视为外部输入的请求,可能修改到内部的业务数据。

第二层为业务应用层,与MVC中的service不同的不是,service中存储着大量业务逻辑。但在应用服务的实现中(以功能点为维度),它负责编排、转发、校验等。

第三层为领域层,聚合根是里面最高话事人。核心逻辑均在聚合根中体现【充血模型】,如果当前聚合根不能处理当前逻辑,需要其他聚合根的配合时,则在聚合根的外部包一层领域服务去实现逻辑。当然,理想的情况是不存在领域服务的。

第四层为基础设施层,为其他层提供技术实现支持

相信这里大家还看见了应用服务层直接调用仓储层的一条线,这条线是什么意思呢?

领域模型的建立是为了控制对于数据的增删改的业务边界,至于数据查询,不同的报表,不同的页面需要展示的数据聚合不具备强业务领域,因此常见的会使用CQRS方式进行查询逻辑的处理。

2.4.2.六边形架构(端口与适配器)

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

对于每一种外界类型,都有一个适配器与之对应。外界接口通过应用层api与内部进行交互。

对于右侧的端口与适配器,我们可以把资源库看成持久化的适配器。

最近爆火的DDD到底是什么?一文带你落地DDD

2.4.3.命令和查询职责分离–CQRS

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

  • 一个对象的一个方法修改了对象的状态,该方法便是一个命令(Command),它不应该返回数据,声明为void。
  • 一个对象的一个方法如果返回了数据,该方法便是一个查询(Query),不应该通过直接或者间接的手段修改对象状态。
  • 聚合只有Command方法,没有Query方法。
  • 资源库只有add/save/fromId方法。
  • 领域模型一分为二,命令模型(写模型)和查询模型(读模型)。
  • 客户端和查询处理器 客户端:web浏览器、桌面应用等 查询处理器:一个只知道如何向数据库执行基本查询的简单组件,查询处理器不复杂,可以返回DTO或其它序列化的结果集,根据系统状态自定
  • 查询模型:一种非规范化的数据模型,并不反映领域行为,只用于数据显示
  • 客户端和命令处理器 聚合就是命令模型 命令模型拥有设计良好的契约和行为,将命令匹配到相应的契约是很直接的事情
  • 事件订阅器更新查询模型
  • 处理具有最终一致性的查询模型

2.4.4.事件驱动架构

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

落地指导与实践:DDD落地之事件驱动模型

  • 事件驱动架构可以融入六边型架构,融合的比较好,也可以融入传统分层架构
  • 管道和过滤器
  • 长时处理过程 主动拉取状态检查:定时器和完成事件之间存在竞态条件可能造成失败 被动检查,收到事件后检查状态记录是否超时。问题:如果因为某种原因,一直收不到事件就一直不过期
  • 事件源 对于聚合的每次命令操作,都至少一个领域事 件发布出去,表示操作的执行结果 每一个领域事件都将被保存到事件存储中 从资源库获取聚合时,将根据发生在聚合上的 事件来重建聚合,事件的重放顺序与其产生顺序相同 聚合快照:将聚合的某一事件发生时的状态快 照序列化存储下来。以减少重放事件时的耗时

三.落地分享

======

3.1.事件风暴

========

EventStorming则是一套Workshop(可以理解成一个类似于头脑风暴的工作坊)方法。DDD出现要比EventStorming早了10多年,而EventStorming的设计虽然参考了DDD的部分内容,但是并不是只为了DDD而设计的,是一套独立的通过协作基于事件还原系统全貌,从而快速分析复杂业务领域,完成领域建模的方法。

最近爆火的DDD到底是什么?一文带你落地DDD

针对老系统内的业务逻辑,根据以上方式进行业务逻辑聚合的划分

例如电商场景下购车流程进行事件风暴

最近爆火的DDD到底是什么?一文带你落地DDD

3.2.场景识别

========

事件风暴结束明确业务聚合后,进行场景识别与层级划分

最近爆火的DDD到底是什么?一文带你落地DDD

3.3.包模块划分

=========

最近爆火的DDD到底是什么?一文带你落地DDD

3.4.迁移说明

========

3.4.1.仓储层

=========

在我们日常的代码中,使用Repository模式是一个很简单,但是又能得到很多收益的事情。最大的收益就是可以彻底和底层实现解耦,让上层业务可以快速自发展。

以目前逆向模型举例,现有

  • OrderDO
  • OrderDAO

可以通过以下几个步骤逐渐的实现Repository模式:

  1. 生成Order实体类,初期字段可以和OrderDO保持一致
  2. 生成OrderDataConverter,通过MapStruct基本上2行代码就能完成
  3. 写单元测试,确保Order和OrderDO之间的转化100%正确
  4. 生成OrderRepository接口和实现,通过单测确保OrderRepository的正确性
  5. 将原有代码里使用了OrderDO的地方改为Order
  6. 将原有代码里使用了OrderDAO的地方都改为用OrderRepository
  7. 通过单测确保业务逻辑的一致性。

有一点要注意,目前我们用mybatis,dao操作都是含有业务含义的,正常的repository不应该有这种方法,目前repository中的含有业务含义的方法只是兼容方案,最终态都要干掉的。

极端DDD推崇者要求在repository中只存在save与byId两个聚合方法。这个当然需要根据实际业务场景来决定,但是还是建议仅保存这两个方法,其他业务需求查询聚合的方法单独开一个queryRepository实现不同数据的查询聚合与页面数据展示。保证数据的增删改入口唯一

3.4.2. 隔离三方依赖-adapter

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

思想和repository是一致的,以调用payApi为例:

  1. 在domain新建adapter包
  2. 新建PayAdapter接口
  3. 在infrastructure中定义adapter的实现,转换内部模型和外部模型,调用pay接口,返回内部模型dto
  4. 将原先业务中调用rpc的地方改成adapter
  5. 单测对比rpc和adapter,保证正确性

3.4.3. 抽离技术组件

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

同样是符合六边形架构的思想,把mqProducer,JsonUtil等技术组件,在domain定义接口,在infrastructure写实现,替换步骤和adapter类似。

3.4.4. 业务流程模块化-application

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

如果是用能力链的项目,能力链的service就可以是application。如果原先service中的业务逻辑混杂,甚至连参数组装都是在service中体现的。那么需要把逻辑归到聚合根中,当前聚合根无法完全包裹的,防止在领域模型中体现。在应用服务层中为能力链的体现。

3.4.5. CQRS参数显式化

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

能力链项目,定义command,query包,通过能力链来体现Command,Query,包括继承CommandService、QueryService,Po继承CommandPo,QueryPo

非能力链项目,在application定义command,query包,参数和类名要体现CQRS。

3.4.6. 战略设计-domain

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

重新设计聚合和实体,可能和现有模型有差异,如果模型差距不大,直接将能力点内的逻辑,迁移到实体中,

将原来调用repository的含业务含义的方法,换成save,同时删除含业务含义的方法,这个时候可以考虑用jpa替换mybatis,这里就看各个子域的选择了,如果用jpa的话 dao层可以干掉。至此,原biz里的大多数类已迁移完成。

四.迁移过程中可能存在的疑问

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

迁移过程中一定会存在或多或少不清楚的地方,这里我分享一下我在迁移的过程中遇到的问题。

最近爆火的DDD到底是什么?一文带你落地DDD

1.领域服务与应用服务的实际应用场景区别

应用服务:可以理解为是各种方法的编排,不会处理任务业务逻辑,比如订单数修改,导致价格变动,这个逻辑体现在聚合根中,应用服务只负责调用。

领域服务:聚合根本身无法完全处理这个逻辑,例如支付这个步骤,订单聚合不可能支付,所以在订单聚合上架一层领域服务,在领域服务中实现支付逻辑。应用服务调用领域服务。

2.聚合根定义的业务边界是什么?

不以表结构数据进行业务逻辑的划分,一个业务体为一块业务。比如一个订单涉及商品,收货地址,发货地址,个人信息等等。以实体与值对象的方式在聚合内进行定义。

3.一个command修改一个聚合时,会关联修改到别的关联表,这个关联表算不算聚合

关联表不算聚合,算值对象

4.应用服务层如果调用rpc是否必须使用adapter

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

最近爆火的DDD到底是什么?一文带你落地DDD

最近爆火的DDD到底是什么?一文带你落地DDD

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

总结

本文从基础到高级再到实战,由浅入深,把MySQL讲的清清楚楚,明明白白,这应该是我目前为止看到过最好的有关MySQL的学习笔记了,我相信如果你把这份笔记认真看完后,无论是工作中碰到的问题还是被面试官问到的问题都能迎刃而解!

MySQL50道高频面试题整理:

最近爆火的DDD到底是什么?一文带你落地DDD

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

总结

本文从基础到高级再到实战,由浅入深,把MySQL讲的清清楚楚,明明白白,这应该是我目前为止看到过最好的有关MySQL的学习笔记了,我相信如果你把这份笔记认真看完后,无论是工作中碰到的问题还是被面试官问到的问题都能迎刃而解!

MySQL50道高频面试题整理:

[外链图片转存中…(img-zomyb6Wx-30)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/138455.html

(0)
上一篇 2024-11-23 21:26
下一篇 2024-11-23 21:33

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信