DDD领域驱动设计
Domain Driven Design
1.概述
影响复杂度的3个要素:规模、结构与变化。控制复杂度的着力点就在这3个要素之上
1.1 领域驱动设计元模型
核心方法论:模型驱动设计,模型驱动设计的核心又是领域模型
为整个业务系统建立的领域模型要么属于核心子领域,要么属于通用子领域
为了保证定义的领域模型在不同上下文表达各自的知识语境,需要引入限界上下文来确定业务能力的自治边界,并考虑通过持续集成来维护模型的统一。
上下文映射清晰地表达了多个限界上下文之间的协作关系
具体方法
- 面向对象分析设计:用例分析,对象职责分解,通用建模
- 四色建模:特定于商业场景建模方式
- CQRS:只对命令类问题领域模型建模,降低建模难度
- 事件风暴:从事件出发建模
- 四层架构:独立的领域层
- 六边形架构:领域模块成为架构核心,不依赖实现
- 事件溯源:只持久化事件,不持久化聚合,解决对象模型和数据库不匹配
1.重构代码
- 1.1 添加领域模块
老代码依赖领域模块,领域模块只实现领域模型代码 - 1.2 分离出有价值代码
老代码内部分离出最有价值的模块,定义这个模块和老代码之间接口,接口非常重要 - 1.3 迁移到领域模型
在领域模块中按照DDD方式实现领域模型,原本老代码中待分离模块变成适配器模块,调用领域模型实现接口
2.实践路径
- 实现模型:使用六边形架构和CQRS实现领域模型,会仓储模式
- 战术建模:事件风暴和DDD设计模型掌握聚合,能解决简单的问题
- 战略建模:用事件风暴对复杂业务建模,掌握限界上下文子领域
- 协作:帮助兄弟团队理解DDD 统一语言,综合敏捷开发,架构治理等
3.六边形架构
DDD追求领域模型代码不对别的代码产生语义依赖,而编译依赖必定导致语义依赖
因此领域模型代码应该不对别的代码产生编译依赖
- 依赖反转:领域模块中要使用非领域模块功能,只需要定义接口,在领域模块外实现该接口
- 不是所有功能都在领域内定义接口,只有那些不可再分解为领域逻辑的功能才定义为接口
- 在领域模块内定义的接口,应该使用领域模型的语言,不要对实现产生语义依赖
4.CQRS
Command and 命令
Query 查询
Responiblity 职责
Segrgation 分离
4.1 职责分离
命令和查询俩类功能代码分离
- 查询模块依赖命令模块
4.2 标准架构
命令和查询通过领域事件集成:命令发布领域事件,查询模块监听事件,构建查询模型
- 采用异步消息队列
- 存储分开,用各自适合的格式存储到设备中
- 领域事件: 是一种领域模型,代表领域已发生的有意义的,不可变,按时间有序
4.3 同事务存储分离
命令和查询构建在一个事务中
优点:简单,没有消息消费引发的问题
缺点: 领域模型和查询模型存储在一个数据库,命令处理延迟高
4.4 共享存储
由仓储负责触发生成查询模型
优点:简单易实现
缺点:查询模型共享领域模型,适应范围窄
4.5 应用范围
当不用CQRS就会污染领域模型时
- 复杂查询:条件复杂,需要冗余数据,搜索
- 高性能查询:需要查询专用数据库,异种查询存储(关系型数据库 缓存 NoSQL)
5.面向对象领域模型
5.聚合上下限
- 问题域看:聚合是紧密联系的一组功能
- 软件设计:内存单元,包含了一组对象,要被整存整取
- 粒度适中:上限不要影响性能,下限不要破坏封装
6.事件风暴
一种头脑风暴形式
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!