小型支付商城 | {DDD重构}
小型支付商城的DDD重构,对比MVC和DDD两种分层架构的设计思想,学习领域驱动的分层方式。
0. 理论基础
DDD(Domain Driven Design)分层架构是一种理论上的设计思想,具体到落地,有洋葱架构、六边形架构等。其主要目标是以领域服务为核心,隔离内部实现与外部资源调用,解耦两者,最终能让程序员更关心项目自身业务的开发。
我们以六边形的DDD分层架构为例,可以将一个工程拆分为:
- api层:用于接口定义,统一入参(Response)对外暴露;好处是对外提供接口描述信息,结合RPC框架(底层是Socket通信+动态代理+反射机制)可实现微服务之间的高效通信,就好像在调用自己定义的实例对象一样。以及规范了响应参数的处理。
- app层:负责config配置和应用启动。这一层可以类比于MVC架构的web(controller层):

- 但在MVC中,web层不仅要负责配置config和yml,要启动项目,也要写controller,都写在这里,如果需要版本迭代,体量增大之后难以维护。
- 在DDD架构中,配置和启动交给了app层,而controller则写在trigger层。
- domain层:DDD思想的核心,依据业务逻辑分为不同的领域,每个领域是所谓的“充血模型”,即有自己的衣帽间,包含:
- 模型对象:model,充血对象
- 仓储服务:repository,调用数据库的接口
- 外部api接口调用定义:port,仅定义接口,满足自己领域中业务逻辑的需要,实现下放到infrastructure层
- 领域服务:service,此处的领域服务仅关注自身核心业务功能的接口定义与实现

- 类比于MVC中的domain层,定义了VO、PO、Req、Res、Dto等用于POJO对象,所有业务的POJO都放在一起,没有自己的衣帽间,部分对象可能由于被共享,添加了两个口袋、一个补丁等进去,使得属性增多。这里的domain层,没有业务逻辑,称之为“贫血模型”。
- infrastructure层:用于承接外部资源的调用。具体地,负责定义http、rpc接口,调用外部。

- trigger层:本身提供到外部的放在这里,用于向外部提供服务。

- types层:用于存放通用信息,包括枚举、工具类、全局异常。相当于之前的common包。
0.2 六边形工程架构
参考xiaofuge的DDD工程模型路书,再次明确六边形架构的特点,会把本身提供到外部的放到trigger,让接口调用、消息监听、任务调度,都可以统一一个入口处理。而对于需要调用外部同类的能力统一放到 infrastructure 基础设施层,包括;数据库、缓存、配置、调用其他方的接口。
0.3 领域模型设计
model 模型对象:
- entity:实体对象。大多数情况下,实体对象Entity与数据库持久化对象PO是1v1的关系。如雇员用户的基本信息、订单信息、配送信息。
- valobj:值对象,用于描述实体对象信息。如一个人,这个雇员的基本level枚举值对象、这个人居住地四级地址对象。这些对象不具有唯一性,也就不具有生命特征,就像你,之后你的衣服,你的胡子。
- aggregate:聚合对象,当我们要写一笔订单入口的时候,需要做事务,事务如果需要一组对象,订单记录、账户记录、库存记录等,这些实体对象+值对象,写入到聚合对象内,一起提交过去。
repository 仓储服务:从数据库等数据源中获取数据,传递的对象可以是聚合对象、实体对象,返回的结果可以是实体对象、值对象。
service 服务设计:这里要注意,聚合对象更应该注重的是和本对象相关的单一简单封装场景,而把一些重核心业务方法到service里实现。
0.4 对象定义小结
在 DDD 领域驱动架构下,对象的使用场景结合各层小结如下。
0.4.1 domain领域层
- entity、vo、aggregate对象,以前的 MVC 下的 XxxVo、XxxReq、XxxRes,现在被领域细分成各个模块下的,实体、聚合、值对象了。
0.4.2 infrastructure基础设施层
- po数据库持久化对象,用于映射数据库表字段,只提供数据库数据。
- dto数据传输对象,这个对象也会在infrastructure层出现,用于与外部的接口对接,比如rpc接口、http接口,出入参的对象,都叫DTO。命名为 XxxRequestDTO、XxxResponseDTO 支付宝的sdk包里就是这样命名的。
0.4.3 api层
- dto对象,接口的出入参,数据传输对象。命名为XxxRequestDTO、XxxResponseDTO
- response<?>对象,包装结果对象,提供code、info、data,准确描述错误码以及data数据,data数据是泛型,用于包装 XxxResponseDTO 结果。
0.4.4 case层
这一层承接 web 的接口编排动作,串联 domain 领域流程。通常2个方案,一个是引入 api 层,定义的对象。另外一个就是多一层转换,在一层定义 api 层对应的 XxxRequestDTO -> XxxRequest、XxxResponseDTO -> XxxResponse
0.5 关于DDD建模方法
DDD的建模过程,是以一个用户为起点,通过行为命令,发起行为动作,串联整个业务。最初来自于用例图的分析,用例图是用户与系统交互的最简表示形式,展现了用户和与他相关的用例之间的关系。通过用例图,我们可以分析出所有的行为动作。
我们将在DDD中用于完成用户行为命令和动作分析的过程,称之为“四色建模”。如下图所示,通过寻找领域事件,发起事件命令,完成领域事件的过程,完成DDD工程建模。
- 蓝色 - 决策命令,是用户发起的行为动作,如:开始签到、开始抽奖、查看额度等。
- 黄色 - 领域事件,过去时态描述。如:签到完成、抽奖完成、奖品发放完成。它所阐述的都是这个领域要完成的终态。
- 粉色 - 外部系统,如你的系统需要调用外部的接口完成流程。
- 红色 - 业务流程,用于串联决策命令到领域事件,所实现的业务流程。一些简单的场景则直接由决策命令到领域事件就可以了。
- 绿色 - 只读模型,做一些读取数据的动作,没有写库的操作。
- 棕色 - 领域对象,每个决策命令的发起,都是含有一个对应的领域对象。
上图左下部分的示意图表达的是:“一个用户,通过一个策略命令,使用领域对象,通过业务流程,完成2个领域事件,调用1次外部接口”的过程。我们在整个 DDD 建模过程中,就是在寻找这些节点。
- 关于业务案例分析,见xiaofuge路书