领域驱动设计2-整体代码设计

1:前言

DDD领域驱动设计,对比(dao+service)的脚本式编程,主要还是将以前的脚本代码拆散,以实体为载体,协调各个模块实现业务功能。DDD领域设计有如下好处:

1:强调实体的概念,将现实世界与软件系统关联起来,便于不同岗位的人达成统一的认知。有助于业务理解和需求讨论。
2:明确业务规则和业务流程,将系统中的隐形业务逻辑在领域层显性展示出来。
3:分模块编写代码,有助于明确和细化代码功能,编写的代码质量更好,可以最大化满足SOLID原则。后续系统升级改造时,可精确定位到需要调整的模块,便于高效的维护业务代码。

SOLID原则指单一职责原则(SRP),开闭原则(OCP),里氏替换原则(LSP),接口隔离原则(ISP)和依赖倒置原则(DIP)。

 

2:设计架构

 

领域驱动代码严格按照洋葱架构设计,同心圆代表应用软件的不同部分,从里向外依次是领域模型,领域服务,应用服务,和最外层容易变化的内容,比如用户界面和基础资源。

洋葱架构主要的原则就是依赖原则,它定义了各层的依赖关系,越往里依赖程度越低,代码级别越高,越是核心能力。外圆代码依赖只能指向内圆,内圆不需要知道外圆的任何情况。

1:领域模型实现领域内核心业务逻辑,它封装了企业级的业务规则。领域模型的主体是实体,一个实体可以是一个带方法的对象,也可以是一个数据结构和方法集合
2:领域服务实现设计多个实体的复杂业务逻辑
3:应用服务实现与用户操作相关的服务组合和编排,它包含了应用特有的业务流程规则,封装和实现了系统所有用例
4:洋葱架构最外层主要提供适配能力,适配能力分为主动适配和被动适配。

 

3:代码架构

翻译为一个请求的调用过程:

1:前端应用传递CQE对象(DTO)到用户接口层,接口层针对不同端进行数据适配,剪裁,值翻译等操作
2:基于SpringValidation等模型做基础数据格式验证
3:应用层的所有接口的入参为DTO,返回值也为DTO,应用层只做业务服务编排,无任何业务逻辑。
  1)应用层通过防腐层(接口)调用远程服务,接口的具体实现放在基础层
  2)应用层进行数据的增删改,需要调用防腐层(接口)保存数据
  3)应用层调用工厂创建实体(简单实体,应用层直接生成)
  4)跨应用的领域事件也在应用层完成
4:领域层中,有多个聚合,每个聚合有多个实体,值对象,领域服务。业务逻辑都放在领域层实现,领域层原则不直接存数据,但是可以仓储接口调用基础层读取数据。原则上领域层尽量不要调用防腐层去请求远程数据,尽量放在应用层实现(不强求)
实体有自己的业务逻辑,跨实体的功能聚合通过领域服务进行操作。领域服务的所有返回值都应该是实体对象
5:基础层中,有防腐层接口和仓储接口的具体业务实现,除此之外其他层中只依赖接口,不依赖具体的实现,面向接口编程。仓储实现的入参与出参都是领域层的实体,仓储实现内部将Entity/VO 与DO的互相转换

 

DTO<-->Entity/VO<-->DO 数据传输

DO(Data Object):数据库映射对象,贫血模型,没有任何功能

Entity/VO :领域中的 实体/值对象,富模型,拥有自己的业务逻辑,内部集成了大量自身相关的业务逻辑

DTO:数据传送对象,贫血模型,没有任何功能

 

 

图中展示了每一层应该持有的对象以及转换逻辑

其中应用层主要做 实体/值对象与DTO的转换

基础层的仓库实现主要做 实体/值对象与DO的转换

4:常规流程

应用层-流程编排

 

微服务B 调用自己的应用层,应用服务B 需要进行4步操作,分别调用自己身领域层的领域服务B和领域服务C 同时调用远程服务A和远程服务C。

应用层无业务逻辑只做流程编排。

5:实体产生-操作步骤

常见的业务场景是,从前端传过来一个对象,需要服务端生成新的实体并存储,此时系统中是不存在这个实体的,例如交易系统中的,单据创建,提交审核单等。一般的流程:

1:应用层获取Command对象
2:应用层通过工厂创建一个实体,简单对象也可以直接new一个,在应用层设置实体的值
3:工厂生成实体的模式,需要工厂获取实体的各个依赖对象,生成领域实体,这个实体也可能是聚合根
4:领域层执行操作,基于传入的实体,调用领域对象的方法对其进行操作,通常是内存操作,不要在领域层进行持久化
5:处理完成,应用层调用仓储接口进行持久化
6:基础服务的仓储实现获得一个实体,可能根据情况将复杂实体转换成多个DO对象后进行数据存储。

posted @ 2022-04-24 10:55  20191018  阅读(234)  评论(0编辑  收藏  举报