187 lines
7.4 KiB
Markdown
187 lines
7.4 KiB
Markdown
# 领域驱动设计
|
||
|
||
领域驱动设计(Domain-Driven Design,DDD)是由埃里克・埃文斯(Eric Evans)提出的一种软件开发方法论,核心是通过深入理解业务领域,将业务逻辑与技术实现紧密结合,从而构建出灵活、可维护且贴合业务的复杂系统。它尤其适合业务逻辑复杂、需求多变的大型应用(如金融、电商、企业 ERP 等)。
|
||
|
||
### **一、DDD 的核心思想**
|
||
|
||
DDD 的核心是 “以领域为中心”,强调开发团队与业务专家深度协作,共同挖掘业务本质(领域知识),并将这些知识转化为软件设计。其目标是:
|
||
|
||
|
||
* 解决复杂业务逻辑的建模问题;
|
||
|
||
* 让软件设计直接反映业务规则,降低技术与业务的鸿沟;
|
||
|
||
* 提高系统的可扩展性和可维护性。
|
||
|
||
### **二、DDD 的核心概念**
|
||
|
||
DDD 通过一系列概念将领域知识结构化,核心概念包括:
|
||
|
||
#### 1. **领域(Domain)**
|
||
|
||
业务所涉及的范围和知识集合,是问题的核心。例如,电商领域包括商品、订单、支付、物流等子领域。
|
||
|
||
#### 2. **子领域(Subdomain)**
|
||
|
||
将复杂领域拆分为更小的、可管理的子领域,分为三类:
|
||
|
||
|
||
|
||
* **核心子领域**:业务的核心竞争力(如电商的订单履约),需重点投入设计;
|
||
|
||
* **支撑子领域**:支持核心业务但非核心(如用户评价),可适度设计;
|
||
|
||
* **通用子领域**:多个子领域共享的功能(如日志、权限),可使用通用组件或第三方工具。
|
||
|
||
#### 3. **限界上下文(Bounded Context)**
|
||
|
||
|
||
|
||
* **定义**:领域模型的边界,在边界内,领域术语、规则、对象的含义是统一的(即 “通用语言”),边界外可能有不同的模型。
|
||
|
||
* **作用**:解决领域模型的歧义性(例如,“订单” 在电商订单系统和财务系统中可能有不同含义),是微服务拆分的重要依据(通常一个限界上下文对应一个微服务)。
|
||
|
||
#### 4. **通用语言(Ubiquitous Language)**
|
||
|
||
|
||
|
||
* 开发团队与业务专家共同定义的语言,包含术语、规则、流程,需贯穿需求分析、设计、编码、测试的全流程。
|
||
|
||
* 例如,在电商领域,“下单”“库存锁定”“支付回调” 等术语需在团队中达成共识,避免歧义。
|
||
|
||
#### 5. **领域模型(Domain Model)**
|
||
|
||
对领域知识的抽象表示,是 DDD 的核心。领域模型通过 “实体”“值对象”“聚合” 等元素构成。
|
||
|
||
#### 6. **实体(Entity)**
|
||
|
||
|
||
|
||
* 具有唯一标识(ID),且其生命周期中标识不变的对象,状态可变化。
|
||
|
||
* 例如:“用户”(ID 唯一,姓名、地址可变)、“订单”(订单号唯一,状态可从 “待支付” 变为 “已发货”)。
|
||
|
||
#### 7. **值对象(Value Object)**
|
||
|
||
|
||
|
||
* 无唯一标识,仅通过属性值来定义,不可变(一旦创建,属性不可修改)。
|
||
|
||
* 用于描述实体的属性或状态。例如:“地址”(由省、市、街道等属性组成,无独立 ID)、“金额”(由数值和货币单位组成)。
|
||
|
||
#### 8. **聚合(Aggregate)**
|
||
|
||
|
||
|
||
* 一组紧密关联的实体和值对象的集合,作为数据修改和事务的最小单元(“聚合根” 是聚合的入口)。
|
||
|
||
* 目的:保证领域模型的一致性,避免复杂的跨对象事务。
|
||
|
||
* **聚合根(Aggregate Root)**:聚合中唯一对外暴露的实体,外部只能通过聚合根访问聚合内的其他对象。例如,“订单” 是聚合根,包含 “订单项”(实体)和 “收货地址”(值对象),外部需通过订单 ID 操作订单项。
|
||
|
||
#### 9. **领域服务(Domain Service)**
|
||
|
||
|
||
|
||
* 当业务逻辑不属于某个实体或值对象时,将其封装为领域服务(无状态,仅处理领域逻辑)。
|
||
|
||
* 例如:“订单结算” 涉及订单、支付、库存多个聚合,需通过领域服务协调。
|
||
|
||
#### 10. **领域事件(Domain Event)**
|
||
|
||
|
||
|
||
* 领域中发生的重要事件(如 “订单支付成功”“库存不足”),用于捕获领域中的状态变化,实现跨聚合 / 限界上下文的通信。
|
||
|
||
* 例如:订单支付成功后,发布 “OrderPaidEvent”,库存系统监听事件并扣减库存,物流系统监听并创建物流单。
|
||
|
||
#### 11. **仓储(Repository)**
|
||
|
||
|
||
|
||
* 封装对聚合的持久化操作(如保存、查询),隔离领域模型与数据存储细节(如数据库、缓存)。
|
||
|
||
* 仓储仅针对聚合根设计,例如 “OrderRepository” 负责订单聚合的持久化。
|
||
|
||
#### 12. **工厂(Factory)**
|
||
|
||
|
||
|
||
* 用于创建复杂的领域对象(如聚合),封装创建逻辑,避免领域模型被创建逻辑污染。
|
||
|
||
### **三、DDD 的分层架构**
|
||
|
||
为了隔离关注点,DDD 通常采用分层架构(与传统三层架构不同,更强调领域层的核心地位):
|
||
|
||
|
||
|
||
1. **用户界面层(UI Layer)**
|
||
|
||
* 负责与用户交互(如 API 接口、网页、APP),处理输入输出,不包含业务逻辑。
|
||
|
||
1. **应用层(Application Layer)**
|
||
|
||
* 协调领域层完成业务用例(如 “下单流程” 需调用订单聚合、支付服务、库存服务),无业务规则,仅负责流程编排。
|
||
|
||
* 依赖领域层,不依赖基础设施层(通过依赖注入反转)。
|
||
|
||
1. **领域层(Domain Layer)**
|
||
|
||
* 核心层,包含领域模型(实体、值对象、聚合、领域服务、领域事件等),封装业务规则和逻辑。
|
||
|
||
* 不依赖其他层(基础设施层的依赖通过接口反转)。
|
||
|
||
1. **基础设施层(Infrastructure Layer)**
|
||
|
||
* 提供技术支持(如数据库持久化、消息队列、缓存、第三方服务集成)。
|
||
|
||
* 实现领域层定义的接口(如 Repository 的数据库实现),支撑应用层和领域层的运行。
|
||
|
||
### **四、DDD 的实践流程**
|
||
|
||
|
||
|
||
1. **事件风暴(Event Storming)**:业务专家与开发团队通过头脑风暴,梳理领域中的事件、命令、实体、聚合等,划分限界上下文,形成通用语言。
|
||
|
||
2. **领域建模**:在限界上下文内,设计实体、值对象、聚合等领域模型,明确聚合根和领域服务。
|
||
|
||
3. **分层实现**:按分层架构编码,领域层优先实现,基础设施层提供技术支撑。
|
||
|
||
4. **持续迭代**:通过反馈优化模型,确保领域模型与业务同步演进。
|
||
|
||
### **五、DDD 与微服务的关系**
|
||
|
||
DDD 是微服务拆分的重要指导思想:
|
||
|
||
|
||
|
||
* 限界上下文是微服务的天然边界(一个限界上下文通常对应一个微服务),确保服务内模型一致,服务间通过接口或事件通信。
|
||
|
||
* 微服务的独立部署、扩展特性,与 DDD 隔离领域复杂度的目标一致。
|
||
|
||
### **六、DDD 的优势与挑战**
|
||
|
||
|
||
|
||
* **优势**:
|
||
|
||
|
||
* 模型贴近业务,易理解和维护;
|
||
|
||
* 隔离复杂业务,提高系统扩展性;
|
||
|
||
* 减少技术与业务的沟通成本。
|
||
|
||
* **挑战**:
|
||
|
||
|
||
* 学习成本高(概念多且抽象);
|
||
|
||
* 适合复杂业务,简单系统可能过度设计;
|
||
|
||
* 依赖团队与业务专家的深度协作,对团队能力要求高。
|
||
|
||
### **总结**
|
||
|
||
DDD 不是一套固定的工具或框架,而是一种 “以业务为中心” 的思维方式。它通过领域建模将复杂业务拆解为可管理的部分,帮助团队构建出既满足业务需求又具备技术灵活性的系统。对于业务复杂、长期演进的系统,DDD 是值得投入的设计方法。
|