![领域驱动设计工作坊](https://wfqqreader-1252317822.image.myqcloud.com/cover/998/51721998/b_51721998.jpg)
1.2.3 领域驱动战术设计
请注意,在DDD的战略设计中,统一语言属于问题空间的范畴,而限界上下文属于解空间的范畴。也就是说,通过战略设计,我们已经完成了从问题空间到解空间的映射。但是,这时的解空间只是一个框架,需要通过DDD的战术设计进行填充。DDD战术设计与业务模型的对应关系如图1-25所示。
![QQ截图20230824184736](https://epubservercos.yuewen.com/418049/30525124507101406/epubprivate/OEBPS/Images/tx025.jpg?sign=1739388216-0LqJAmXMGeGKIpKQRJ8FaYlhPiWpbCfc-0-4c95f5793bdde1600722eac633e22e5e)
图1-25 业务模型与战术设计的对应关系
1.领域对象
在传统软件开发中,业务是由数据驱动的,开发人员从数据的角度来规划对象的组织形式,并以面向数据库的方式对这些数据对象进行设计和建模,每个业务对象只包含业务数据和结构的定义,并不具备业务操作能力,这就是所谓的贫血模型(Anaemic Model)。
虽然以数据作为主要关注点的开发模式也能完成对系统的构建,但我们认为面向领域的模型对象才是能够表达统一语言的有效载体。究其原因,在于很多对象并不能简单地通过它们的数据属性来定义,而是应该具有一系列的标识和行为定义。在DDD中,领域模型对象包括三大类,如图1-26所示。
![](https://epubservercos.yuewen.com/418049/30525124507101406/epubprivate/OEBPS/Images/tx026.jpg?sign=1739388216-6T3JvqBcilt7KrJYslTZJmHa8Qtj2yz9-0-bf57260d0dc5f3789770c679cfab44d0)
图1-26 领域模型对象的三大类
在图1-26中,有聚合、实体和值对象3类领域对象,我们认为这些领域对象才是能够表达统一语言的有效载体。
● 聚合。聚合的核心思想在于简化对象之间的关联关系,一个聚合内部的所有对象只能通过聚合对象来进行访问,从而有效降低了对象之间的交互复杂度。
● 实体。实体是聚合内部具有唯一标识的一种业务对象,具有丰富的操作行为、状态可变性,以及完整生命周期。
● 值对象。值对象有点类似贫血模型对象,只关心对象的数据属性而不具备操作行为。值对象是不变对象、没有唯一标识且通常不包含业务逻辑。
2.领域服务
我们可以将业务模型中的业务逻辑抽象为一组业务规则。业务规则从概念上说通常不属于任何一个独立的对象,而是涉及一组领域模型对象之间的交互和操作。当领域模型中某个重要操作无法由单个聚合或实体完成时,应该为模型添加一个独立的访问入口,这就是领域服务(Domain Service),如图1-27所示。
![QQ截图20230824185515](https://epubservercos.yuewen.com/418049/30525124507101406/epubprivate/OEBPS/Images/tx027.jpg?sign=1739388216-vSXU6TxsfxKjUUTJUGVg0h6fWRmu5wNY-0-e5913a6bda6e5273054b57484e3d7679)
图1-27 领域服务的定位
从图1-27可以看出,领域服务的构建涉及多个领域模型对象之间的交互和协作,这是单个领域模型对象所不能完成的操作。
3.领域事件
现实中很多场景可以抽象为事件,如某一个操作发生时发送一条消息、出现了某种情况执行某个既定业务操作等。本质上,事件代表的是一种业务状态的变化,是一种独立的建模对象,在DDD中被称为领域事件(Domain Event),如图1-28所示。
![](https://epubservercos.yuewen.com/418049/30525124507101406/epubprivate/OEBPS/Images/4.jpg?sign=1739388216-obTstdCAc5EiDOdnQbVvXb5eahzMVU5s-0-f07dfd376167628b76f5de7d94bdb2cf)
图1-28 领域事件的执行流程
领域事件实质上就是将领域中发生的活动建模为一系列离散事件。领域事件也是一种领域对象,是领域模型的重要组成部分。
4.资源库
对于任何一个系统,业务数据都需要进行统一的管理和维护,开发人员应将数据保存到各种数据持久化媒介中。我们认为系统中应该存在一个专门针对数据访问的入口,通过该入口可以对所有领域模型对象进行遍历。在DDD中,资源库(Repository)实际上充当了领域模型对象提供者的角色,如图1-29所示。
![QQ截图20230824190444](https://epubservercos.yuewen.com/418049/30525124507101406/epubprivate/OEBPS/Images/tx028.jpg?sign=1739388216-587SH413M84Frh1xcx3OLIunWznbxhTD-0-a982824e7542ebcb9c5f3c3209277e85)
图1-29 资源库的定位
简单来说,资源库用于实现对业务数据的持久化管理,同时帮助开发人员屏蔽数据访问过程中的技术复杂性。
5.应用服务
DDD中的应用服务(Application Service)提供了类似数据传输对象(Data Transfer Object,DTO)模式和外观模式(Facade Pattern)的功能。我们希望为系统中的一组接口提供一个一致的界面,从而使其更易用,这就是应用服务的价值,如图1-30所示。
![](https://epubservercos.yuewen.com/418049/30525124507101406/epubprivate/OEBPS/Images/tx029.jpg?sign=1739388216-9rLISJyiAljxKdUHAHmZHjr0cmtEUchO-0-cdd9f63d0dbaefec899e56cedfb75589)
图1-30 应用服务的定位
对于应用服务,我们不应该放置任何与业务逻辑相关的操作,而是仅完成来自用户界面或外部系统的集成需求,所以是很薄的一层技术组件。
到此,我们完成了从业务模型到DDD方法的完整映射,读者可以结合图1-31中的内容进行总结和回顾。
![](https://epubservercos.yuewen.com/418049/30525124507101406/epubprivate/OEBPS/Images/tx030.jpg?sign=1739388216-coQyvBAXU0vhTmoLe3a0NSrDGVdT6we9-0-b2c124500d1626ea775390fe58b39999)
图1-31 业务模型与DDD之间的映射关系
请注意,图1-31中DDD的各个组件并不是位于同一层次的,各个限界上下文都应该包括战术设计的所有技术组件,如图1-32所示。
![](https://epubservercos.yuewen.com/418049/30525124507101406/epubprivate/OEBPS/Images/tx031.jpg?sign=1739388216-GWtVDTe6Sxil2FJswLkfbUSA9AF4iMiw-0-10bdfdd83999b158e3fd6f58d3b19342)
图1-32 限界上下文和战术设计技术组件示意图