DDD(Domain-Driven Design)
参考
参考自知乎文章与ai对话
一种软件设计方法论,强调围绕业务领域建模,并通过与领域专家的紧密合作来构建系统。 简单来说,DDD的目标是让软件的结构和语言与业务逻辑保持一致,从而更好地解决复杂的业务问题
why?
- 以电商系统为例,订单处理逻辑可能分散在 「订单控制器」、「支付服务」、「库存模块」 等多个技术组件中,「账户」 概念在代码中可能仅作为数据实体,缺少存款、转账等核心业务规则的封装。DDD 的核心目标之一,是通过领域模型驱动设计,让代码结构与业务领域结构保持一致。例如:
- 「订单创建 - 支付 - 发货」 全流程封装在 「订单聚合」 中,确保业务规则的完整性
- 「账户」 实体不仅包含余额属性,还包含存款、转账等领域方法,体现 「金融账户」 的业务本质
- 我们修改业务时可能只需要修改这个模型。而传统可能需要影响多个模块
What?
Domain
- 问题域(Promblem Domain) : 需要解决的业务问题集合,如 「电商平台的订单管理」
- 核心域: 关键业务(在线教育: 课程编排、学习路径设计)
- 支撑域: 支持核心业务的辅助功能(教师管理、学生档案)
- 通用域: 各行业通用功能(支付接口、消息推送)
- 解空间(Solution Domain) : 字面理解即可
Domain Model
- 实体(Entity): 带唯一ID的领域对象,我们在其中封装所有与他相关的业务规则,使数据和逻辑不分离
-
值对象(Value Object) : ?
- 实体是可变状态但需要持续追踪的带唯一标识的对象(一个人的年龄等可以改变,但其身份证号码不变)
- 值对象也是对象,但是我们并不需要它改变,它一旦改变就应该变成一个新的值对象
值对象通过其属性的值来定义,一张紫色的100元钞票,跟另一张紫色的100元钞票完全等同,你只关心它的面额和颜色,不关心它是哪一张。当你试图改变它时,比如给100元加上50元,你得到的是一个全新的、代表150元的值对象,而不是修改原来的100元。
不变性是关键。它让值对象可以被自由共享,不必担心副作用。任何“修改”操作都应该返回一个新的值对象实例。 - 地址在"地址管理"功能中,需要维护地址簿以及进行修改删除,我们需要追踪每个地址的连续性,所以作为实体拥有“地址id”,在“订单”上下文中我们只关心地址是什么而不关心是哪个地址,因此作为值对象。
-
聚合(Aggregate): 通过聚合根把一组相关的实体和值对象封装在一个事务边界,只能通过访问聚合根来处理内部对象,一定程度保证了内部对象的数据一致性与同步性
- 领域服务: 其业务逻辑不适合归属到任何实体/值对象,或者操作涉及多个领域对象协作时单独出来的类
- 仓储(Repository): 封装数据访问细节,提供领域对象的CRUD接口,作为模型与数据储存沟通的桥梁
How?
- 分出领域
- 构建领域组件
- 聚合设计原则
- 单一职责:每个聚合只负责一个业务概念(如 「订单」 聚合不处理支付细节)
- 最小边界:聚合边界应尽可能小,避免包含无关对象
- 一致性边界:聚合内部确保业务规则一致性(如订单总价 = 订单项价格之和
- 领域事件设计: 本质就是异步通信,实现不同聚合之间的协作
- 聚合设计原则
代码结构
- 分层架构设计
┌─────────────────────┐ ┌─────────────────────┐ │ 表示层 │ │ 用户界面/API │ │ (Presentation) │-----> │ (Web/Mobile API) │ └─────────────────────┘ └─────────────────────┘ │ │ ▼ ▼ ┌─────────────────────┐ ┌─────────────────────┐ │ 应用层 │ │ 应用服务/流程编排 │ │ (Application) │-----> │(OrderApplicationService) └─────────────────────┘ └─────────────────────┘ │ │ ▼ ▼ ┌─────────────────────┐ ┌─────────────────────┐ │ 领域层 │ │ 领域模型/业务逻辑 │ │ (Domain) │-----> │(OrderAggregate) │ └─────────────────────┘ └─────────────────────┘ │ │ ▼ ▼ ┌─────────────────────┐ ┌─────────────────────┐ │ 基础设施层 │ │ 数据持久化/外部集成 │ │ (Infrastructure) │-----> │(OrderRepositoryImpl)│ └─────────────────────┘ └─────────────────────┘