https://cloud.tencent.com/developer/article/1662032
一. DDD 简述
DDD (Domain-Driven Design),即领域驱动设计是思考问题的方法论,用于对实际问题建模,它以一种领域专家、设计人员、开发人员都能理解的通用语言作为相互交流的工具,然后将这些概念设计成一个领域模型。由领域模型驱动软件设计,用代码来实现该领域模型。所以,DDD 的核心是建立正确的领域模型。
二. 领域模型
2.1 领域模型
定义上说,领域模型是对具有某个边界的领域的一个抽象,反映了领域内用户业务需求的本质;领域模型是有边界的,只反映了我们在领域内所关注的部分,确保了我们的软件的业务逻辑都在一个模型中,这样对提高软件的可维护性、业务s可理解性以及可重用性方面都有很好的帮助。领域模型只反映业务,和任何技术实现无关,它不仅能反映领域中的一些实体概念(如货物,书本,应聘记录,地址等),还能反映领域中的一些过程概念(如资金转账等)。 领域模型贯穿软件分析、设计,以及开发的整个过程,领域专家、设计人员、开发人员通过领域模型进行交流,彼此共享知识与信息。了让领域模型看的见,我们需要用一些方法来表示它。图是表达领域模型最常用的方式,但并不是唯一的表达方式,代码、文字描述也能表达领域模型。
2.2 通用语言
领域驱动设计的一个核心的原则是使用一种基于模型的语言。因为模型是软件满足领域的共同点,它很适合作为这种通用语言的构造基础。使用模型作为语言的核心骨架,要求团队在进行所有的交流是都使用一致的语言(包括演讲、文字和图形),需要确保团队使用的语言在所有的交流形式中看上去都是一致的,这种语言被称为**通用语言 (Ubiquitous Language)**。在建模过程中,通用语言广泛尝试于推动软件专家和领域专家之间的沟通,从而发现要在模型中使用的主要的领域概念。
2.3 领域建模思考问题
- 我们设计领域模型时不能以用户为中心作为出发点去思考问题,不能老是想着用户会对系统做什么;而应该从一个客观的角度,根据用户需求挖掘出领域内的相关事物,思考这些事物的本质关联及其变化规律作为出发点去思考问题。
- 领域模型是排除了人之外的客观世界模型。
- 虽然领域模型包含人所扮演的参与者角色,但是一般情况下不要让参与者角色在领域模型中占据主要位置。如果以人所扮演的参与者角色在领域模型中占据主要位置,那么各个系统的领域模型将变得没有差别。因为软件系统就是一个人机交互的系统,都是以人为主的活动记录或跟踪。比如:
- 论坛中如果以人为主导,那么领域模型就是:人发帖,人回帖,人结贴,等等;
- DDD的例子中,如果是以人为中心的话,就变成了:托运人托运货物,收货人收货物,付款人付款等等;
- 因此,当我们谈及领域模型时,已经默认把人的因素排除开了,因为领域只有对人来说才有意义,即人是在领域范围之外的,如果人也划入领域,领域模型将很难保持客观性。
- 领域建模是建立虚拟模型让我们现实的人使用,而不是建立虚拟空间,去模仿现实。
- 虽然领域模型包含人所扮演的参与者角色,但是一般情况下不要让参与者角色在领域模型中占据主要位置。如果以人所扮演的参与者角色在领域模型中占据主要位置,那么各个系统的领域模型将变得没有差别。因为软件系统就是一个人机交互的系统,都是以人为主的活动记录或跟踪。比如:
例:以 DDD 之父的货物运输系统为例,他描述领域模型如下:
- 一个货物 (Cargo) 涉及多个客户(Customer,比如托运人、收货人、付款人),每个客户承担不同的角色;
- 货物只有一个运送目标;
- 由一系列规格 (Specification) 的运送动作 (Carrier Movement) 来完成目标的运输。
由上面可以看到,上述这段描述完全以货物为中心,把客户看成是货物在某个场景中可能会涉及到的关联角色。他完全没有从用户的角度去描述领域模型,而是以领域内的相关事物为出发点,考虑这些事物的本质关联及其变化规律的。 其实如果以用户为中心来思考领域模型的思维,这只是停留在需求的表面,而没有挖掘出真正的需求的本质。我们在做领域建模时需要努力挖掘用户需求的本质,这样才能真正实现用户需求。
三. 领域驱动分层架构
- 用户界面/展现层:负责向用户展现信息以及解释用户命令。更细的方面来讲就是:
- 请求应用层以获取用户所需要展现的数据;
- 发送命令给应用层要求其执行某个用户命令;
- 应用层:很薄的一层,定义软件要完成的所有任务。对外为展现层提供各种应用功能(包括查询或命令),对内调用领域层(领域对象或领域服务)完成各种业务逻辑,应用层不包含业务逻辑。
- 领域层:负责表达业务概念,业务状态信息以及业务规则,领域模型处于这一层,是业务软件的核心。
- 基础设施层:本层为其他所有层提供通用的技术能力,包括提供了层间的通信,为领域层实现持久化机制等。总之,基础设施层可以通过架构和框架来支持其他层的技术需求;
四. 领域驱动设计的模式
目录
4.5 聚合 (Aggregate)、聚合根 (Aggregate Root)
4.1 关联的设计
关联本身不是一个模式,但它在领域建模的过程中非常重要,所以需要在探讨各种模式之前,先讨论一下对象之间的关联该如何设计。我觉得对象的关联的设计可以遵循如下的一些原则:
- 关联尽量少,对象之间的复杂的关联容易形成对象的关系网,这样对于我们理解和维护单个对象很不利,也很难划分对象与对象之间的边界;反过来,减少关联有助于简化对象之间的遍历;
- 对多的关联也许在业务上是很自然的,通常我们会用一个集合来表示一对多的关系。但我们往往也需要考虑到性能问题,尤其是当集合内元素非常多的时候,此时往往需要通过单独查询来获取关联的集合信息;
- 关联尽量保持单向的关联;
- 在建立关联时,我们需要深入去挖掘是否存在关联的限制条件,如果存在,那么最好把这个限制条件加到这个关联上;往往这样的限制条件能将关联化繁为简,即可以将多对多简化为一对多,或将一对多简化为一对一;
4.2 实体 (Entity)
实体就是领域中需要唯一标识的领域概念。假设有两个实体,如果唯一标识不一样,那么即便实体的其他所有属性都一样,我们也认为他们两个不同的实体。因为实体有生命周期,实体从被创建后可能会被持久化到数据库,然后某个时候又会被取出来。所以,如果我们不为实体定义一种可以唯一区分的标识,那我们就无法区分到底是这个实体还是哪个实体。 我们不应该给实体定义太多的属性或行为,而应该寻找关联,发现其他一些实体或值对象,将属性或行为转移到其他关联的实体或值对象上。
例: