DDD 架构
近期在学习领域驱动设计(Domain-Driven Design,简称 DDD),其与传统的 MVC 设计模式存在较大差异,在此简单记录我的认识。
概述
传统的 MVC
MVC(Model-View-Controller)将 Web 应用划分为三层:模型层(Model)、视图层(View)和控制器层(Controller)
模型层 Model:
负责处理数据和业务逻辑,以及对象关系映射,是系统核心,包含以下内容:
- 数据实体类:描述业务对象,如用户
- 业务逻辑:通过服务(Service)实现业务逻辑,如用户注册
- 数据访问对象(DAO):负责与数据库交互,执行 CRUD
模型层的职责是封装业务逻辑和数据操作,确保数据的一致性
视图层 View:
负责用户交互与数据展示,是用户与应用程序进行交互的窗口,在 Web 应用中包括 HTML、JSP 等页面,专注于数据展示
控制器层 Controller:
负责 Model 与 View 之间的数据流动,属于桥梁角色,不处理数据和展示逻辑,而是专注于流程控制
DDD
DDD 是一个以业务为核心,用代码精确表达业务概念和规则,并作为团队通用沟通基础的抽象系统。不仅可以用于微服务设计,也适用于传统的单体应用,其核心思想是:软件的核心复杂性不在于技术,而在于业务领域本身。
DDD 关注业务与技术的断层,是以产品为导向。并不是用户所使用的产品,而是整个产品的业务逻辑。其代码往往直接映射现实世界概念,贴近业务。
其关键要素包括:
- 领域(Domain):
- 软件所要解决的具体问题的领域,理解并定义清楚业务需求是 DDD 的基础
- 领域模型(Domain Model):
- 对领域的抽象和表达,通过一组类、对象、方法来描绘和实现业务领域的概念与规则
- 限界上下文(Bounded Context):
- 指一个子系统的业务范围,领域模型在每个限界上下文内都有特定的含义。
- 在不同的上下文中,同一术语可能有不同的定义。
DDD 基本组成
领域 Domain
问题域(Problem Domain):需要解决的业务问题集合
解空间(Solution Domain):软件系统实际实现的解决方案范围
根据业务重要性,问题域可分解为:
- 核心域:决定产品竞争力的关键业务
- 支撑域:支持核心业务的辅助功能
- 通用域:各行业通用的功能
领域模型 Domain Model
领域模型是 DDD 的核心,是对业务领域的形式化表达,有以下组成:
- 实体(Entity)
- 具有唯一标识的领域对象,通过唯一 ID 区分,状态可变
- 封装与自身相关的业务规则,避免数据与逻辑分离
- 值对象(Value Object)
- 属性即本质的不可变对象,无独立 ID,通过属性组合定义
- 属性全封装,创建后不可修改,相等性基于属性值而非引用
- 聚合(Aggregate)
- 由实体和值对象组成的集群,通过聚合根(Aggregate Root)统一管理边界和一致性
- 外部只能通过聚合根访问内部对象,聚合内部维护数据一致性,不同聚合间通过领域事件通信,避免直接关联
- 领域服务(Domain Service)
- 无归属业务逻辑的载体
- 适用于业务逻辑不适合归属到任何实体或值对象(如跨聚合的操作)、操作涉及多个领域对象协作
- 仓储(Repository)
- 领域模型与数据存储的桥梁,封装数据访问细节,使领域模型与持久化技术解耦
- 提供领域对象的 CRUD 接口(基于领域模型而非数据库表)
限界上下文 Bounded Context
本质是定义术语的适用范围,避免同一概念在不同场景下的语义冲突
不同限界上下文间通过以下模式协作:
- 防腐层(Anticorruption Layer):隔离外部上下文的影响,一般通过为外部系统提供独立的接口,避免外部系统的变化影响到内部系统(如订单上下文通过防腐层调用支付上下文的接口)
- 开放主机服务(Open Host Service):定义标准化接口供外部上下文使用
- 共享内核(Shared Kernel):多个上下文共享部分领域模型(如货币、日期模型)
通用语言 Ubiquitous Language
团队沟通的统一语义,即领域专家、开发人员、产品经理使用相同的业务术语,术语定义在代码、文档、交流中保持一致
DDD 架构分层
DDD 建议采用分层架构,通常包括以下四层:
- 表示层(也叫接口层,用户界面与 API,展现数据与解释用户输入)
- 应用层(协调领域层和表示层之间的交互,处理用例逻辑)
- 领域层【核心】(领域模型、业务逻辑,仓储的接口)
- 基础设施层(支持其他三层,数据持久化、外部集成、层间通信,仓储的实现)
DDD 设计
战略设计
战略设计关注的是宏观层面的模块划分和关系,即如何合理划分系统和模块,确保各模块之间的松耦合。
主要从业务视角出发,建立业务领域模型,划分领域边界,建立通用语言的限界上下文,限界上下文可以作为微服务设计的参考边界。战略设计会建立领域模型,领域模型可以用于指导微服务的设计和拆分。包括:
- 划分限界上下文(根据业务需求和领域逻辑进行合理的模块划分)
- 集成策略(定义不同上下文之间的集成方式)
- 反腐层(防止外部系统的影响,保持内部系统的独立性)
战术设计
战术设计关注的是在单个限界上下文内部,如何用代码具体实现模型。
从技术视角出发,侧重于领域模型的技术实现完成软件开发和落地。包括聚合根、实体、值对象、领域服务、领域事件、应用服务和仓储等代码逻辑的设计和实现。
一些元素的具体说明:
- 聚合根:是聚合的入口点。外部对象只能通过聚合根来引用聚合内的对象。聚合根负责保证聚合内的所有对象满足业务规则
- 领域服务:当某个操作或业务逻辑不适合放在实体或值对象中时(因为它涉及多个实体,或者是一个无状态的流程),就将其封装在领域服务中。
- 领域事件:用于表示在领域中所发生的、对业务有重要意义的事情。它通常由聚合根触发,用于在限界上下文内部或之间进行异步通信,实现最终一致性。
- 仓储:只用于聚合根。它抽象了数据持久化的机制,让领域层无需关心数据是如何存储和获取的。其接口定义在领域层,实现在基础设施层。
- 应用服务:
- 位于领域模型之上,是系统的入口点。它不包含任何业务逻辑,职责是协调任务、管理事务、用户授权。
- 接收用户的请求(如数据传输对象 DTO),调用领域模型(实体、领域服务)来完成业务操作,最后将结果返回。
应用层的应用服务
应用层通过应用服务接口来暴露系统的全部功能,将要实现的功能委托给一个或多个领域对象来实现,隐藏了领域层的复杂性及其内部实现机制。
除了定义应用服务之外,在该层我们可以进行安全认证,权限校验,持久化事务控制,或者向其他系统发生基于事件的消息通知,另外还可以用于创建邮件以发送给客户等。
领域事件
将领域中所发生的活动建模成一系列的离散事件。每个事件都用领域对象来表示,表示领域中所发生的事情。领域事件需要基础设施的支持,能较好完成领域模型之间的解耦,映射到微服务架构时,可以解耦微服务
领域事件包括:事件发布、事件存储、事件分发、事件处理
