引子

不知今年吹了什么风,忽然 DDD 领域驱动设计进入大家视野。该思想源于 2003 年 Eric Evans 编写的 “Domain-Driven Design领域驱动设计” 简称 DDD,Evans DDD 是一套综合软件系统分析和设计的面向对象建模方法。刚好公司领导强力推荐这个,抱着学习的心态,耗时 5 个月,体验了一把:“DDD从入门到弃坑”

思想

学习网站

服务器后端发展三个阶段

DDD领域驱动设计架构 ddd领域驱动设计案例_领域模型


服务器后端发展三个阶段:

  1. 面向过程脚本:初始简单,业务复杂后,维护难度指数上升。–>基本不为主流使用
  2. 面向数据库表:初始难度中,业务复杂后,维护难度延迟后再指数上升。—>目前市面上主流
  3. 面向业务模型:DDD+SOA 微服务的事件驱动的 CQRS 读写分离架构:应付复杂业务逻辑,以聚合模型替代数据表模型,以并发的事件驱动替代串联的消息驱动。真正实现以业务实体为核心的灵活拓展。初始难度高,业务复杂后,维护难度线性上升(已很不错)
DDD最大特点

DDD 革命性在于:领域模型准确反映了业务语言,而传统微服务数据对象除了简单 setter/getter 方法外,没有任何业务方法,即失血模型,那么 DDD 领域模型就是充血模型(业务方法定义在实体对象中)

落地
领域模型设计

以渠道中心(一个微服务)作为例子来做领域模型设计,核心就是设计2个图,一个是战略设计图(宏观) ,一个是战术设计图(细节)

  1. 领域战略设计图
    战略设计图是从一个限界上下文的角度出发去分析业务场景。主要是宏观上的核心域、子域、实体关系图。demo如下图:
  2. DDD领域驱动设计架构 ddd领域驱动设计案例_DDD领域驱动设计架构_02

  3. 领域战术设计图
    战术设计图是从一个限界上下文的角度出发去分析业务场景。细化到核心业务字段、领域实体、值对象、领域服务、领域事件等等。基本上这个图画完,代码已经知道怎么写了。demo 如下图
  4. DDD领域驱动设计架构 ddd领域驱动设计案例_java_03

技术实现

整体项目框架分层图如下所示

DDD领域驱动设计架构 ddd领域驱动设计案例_java_04


如上图,4 层典型 DDD 分层结构:

  1. 展现层:controller 层。无业务逻辑
  2. 应用服务层:此层可以包含查询逻辑,但核心业务逻辑必须下沉到领域层
  3. 领域服务层:业务在这里组装。仓储(资源库)接口在此层定义
  4. 基础设施层:仓储(资源库)实现层 + PO 持久化层

注:

  1. 简单查询不涉及业务,是可以直接从应用层直接穿透到 PO 查询,不需要经过 domain 层。如下图所示,DDD 本身是不限制非业务类操作跨层调用的
  2. DTO 是不能存在于 domain 层的,DDD 设计不认为 DTO 是业务对象,entity 才是或者传值简单数据类型也是可以的
服务调用问题
  1. 域内调用
    领域内调用,随便调用,丝般顺滑。至于实现,可以由一个核心域的仓储实现层(第四层)去实现多个 Repository 接口。(比如这里A是核心域的实体名,B是支撑域、通用域等)
  2. 跨域调用

    跨域分为
  3. 同上下文跨域:ACL层 -> Adapter适配器层 -> 调用其它域的 repository -> 不得已才使用,不推荐使用
    推荐:(1):使用领域事件 eventbus 来做解耦;(2)考虑是否有可能合并为一个领域
  4. 跨上下文(肯定跨域):ACL层 -> Adapter适配器层 -> f eign调用
包结构

DDD领域驱动设计架构 ddd领域驱动设计案例_跨域_05


DDD领域驱动设计架构 ddd领域驱动设计案例_DDD领域驱动设计架构_06

  1. 展现层:Controller
    仅做接口的入口定义和编排转发,不做任何的业务处理
  2. 应用服务层:application
    负责接口参数 DTO 的简单校验以及 DTO 和实体值对象的数据转换,对于简单的业务,也可以在应用层加载实体直接执行实体行为方法
  3. 领域层:
  • 模型:根据领域模型分析领域内各实体、聚合、聚合根、值对象等,这些对象在 *.domain.model 定义,实体内的行为方法只负责维护实体自身的生命周期和状态
  • 行为:领域内各实体、聚合、聚合根等,会有相应的行为,在 *.domain.model 包下定义行为方法
  • 领域服务:领域提供的接口服务,需要定义在 *.domain.service 包下,业务相关的前置业务判断、多个实体或值对象的行为逻辑处理等,都在领域服务中实现,需要注意的是并不是每个实体都有一个对应的领域服务,但是依赖多个实体的行为方法,最好根据这个业务模块是建立一个领域服务
  • 仓储:领域服务或上层应用服务需要使用到的基础设施层,包括 DB、Feign 调用等,定义在 *.domain.repository 下,在 *.infrastructure.repository 下实现
  1. 适配层
    在 acl 包下的 feign 定义依赖外部的接口,并在 acl 的 adapter 包编写转换,由仓储层操作实体时调用
  2. 持久层
    与常用 DAO 定义一致,由仓储层操作实体时调用
总结

DDD 可以尝试,但不建议主流业务硬上。建议浅尝即止。(据我所知,业内连阿里巴巴都没有大面积推广)