领域驱动设计概念
1.领域
领域指的是范围或边界,在研究和解决业务问题时,DDD会按照一定的规则将业务领域进行细分。当领域被细分到一定程度后,DDD会将问题范围限定在特定的边界内(也就是领域),并在这个边界内建立领域模型,进而用代码实现该领域模型,解决相应的业务问题。DDD的领域指的就是边界,它确定了要解决的业务问题领域。只要确定了应用所属的领域,这个应用的核心业务,即要解决的关键问题和问题范围的边界就基本确定了。因为领域的本质是问题领域,而问题领域可能根据需要会被逐层细分,所以领域可被分解为子领域,子领域或可被继续分解为子子领域等。
2.子领域
领域可以被进一步划分为子领域,每个子领域都对应一个更小的问题领域,表现更小的业务范围。子领域的核心作用是解决划分问题领域的问题。
通过子领域细分,逐步缩小需要解决的问题领域,构建合适的领域模型。每一个细分的子领域都会有一个知识体系,也就是 DDD 的领域模型。当所有子领域建模完成后,也就建立了全域的知识体系,即建立了全域的领域模型。
3.限界上下文
为了避免相同的语义在不同的上下文环境中产生歧义,DDD在战略设计上提出了“限界上下文”这个概念,用来确定语义所在的语言边界。限界上下文就是指为封装通用语言和领域模型提供上下文环境,保证领域之内的一些术语、业务相关对象等(通用语言)有一个确切的含义,没有二义性。通过限界上下文,就可以在统一的领域边界内使用统一语言进行交流。
4.领域事件
领域事件是领域模型中非常重要的一部分,用来表示领域中发生的事件。领域事件将导致进一步的业务操作,在实现业务解耦的同时,还有助于形成完整的业务闭环。当领域事件发生在微服务内的聚合之间时,领域事件发生后将完成事件实体构建和事件数据持久化,发布方聚合将事件发布到事件总线,订阅方接收事件数据完成后续业务操作。
5.实体
DDD中的实体对象拥有唯一标识符,且标识符在历经各种状态变更之后仍能保持一致。对实体对象重要的不是其属性,而是其延续性和标识,对象的延续性和标识会跨越甚至超出应用的生命周期。实体是具有持久化ID的对象,即使两个实体具有相同的属性值,但是只要ID不同,这两个实体也会被认为是不同的对象。实体是领域模型中非常重要的对象,它在建模过程的一开始就应该被考虑到,决定一个对象是否需要成为一个实体也很重要。实体的业务形态在DDD的不同设计过程中也有可能是不同的。
实体的领域模型形态:在战略设计中,实体是领域模型中一个重要的对象,领域模型中的实体是多个属性、操作或行为的载体。在事件风暴中,我们可以根据命令、操作或者事件找出产生这些行为的业务实体对象,进而按照一定的业务规则将依存度高和业务关联紧密的多个实体对象与值对象进行聚类,形成聚合。
实体的代码形态:在代码模型中,实体的表现形式是代码中的类,这个类包含了实体的属性和方法,通过这些方法实现实体自身的业务逻辑。在 DDD 中,与实体相关的所有业务逻辑都在该实体的类的方法中实现,跨多个实体的领域逻辑则在领域服务中实现。
实体的运行形态:在应用运行过程中,实体以领域对象(DO)的形式存在,每个实体对象都有唯一的ID。我们可以对一个实体对象进行多次修改,修改后的数据和原来的数据可能会大不相同。但由于它们拥有相同的ID,因此它们依然是同一个实体。比如商品是一个实体,通过唯一的商品ID来标识,不管这个商品的数据如何变化,商品的ID一直保持不变,说明始终是同一个商品。
实体的数据库形态:与传统数据模型设计优先不同,DDD是先构建领域模型的,针对实际业务场景构建实体对象和行为,再将实体对象映射到数据持久化对象上。在将领域模型映射到数据模型上时,一个实体可能对应零个、一个或多个数据持久化对象。在大多数情况下,实体与持久化对象是一对一的关系。在某些场景中,有些实体只是暂驻静态内存的运行态实体,它们不需要持久化。
6.值对象
用来描述领域的特殊方面且不需要有标识符的对象,就被称为值对象。因为没有标识符,值对象可以被轻易地创建或丢弃。值对象描述了领域中的不可变对象,它将不同的相关属性组合成一个概念整体。当度量和描述改变时,可以用另外一个值对象予以替换。
本质上,实体是看得到、摸得着的实实在在的业务对象,实体具有业务属性、业务行为和业务逻辑。而值对象只是若干个属性的集合,只有数据初始化操作和有限的不涉及修改数据的行为,基本不包含业务逻辑。值对象的属性集合虽然在物理上被独立出来,但在逻辑上其仍然是实体属性的一部分,用于描述实体的特征。
7.聚合
领域模型内的实体和值对象就好比个体,而能让实体和值对象协同工作的组织就是聚合,它用来确保这些领域对象在实现共同的业务逻辑时数据的一致性。聚合是由业务与逻辑紧密关联的实体和值对象组合而成的,聚合是数据修改和持久化的基本单元。一个限界上下文内可能包含多个聚合,每个聚合都有一个根实体,叫作聚合根。聚合根的主要作用是避免由于复杂数据模型缺少统一的业务规则控制,而导致实体之间数据的不一致。
8.服务
在领域建模过程中,有些概念很难被映射成对象。对于对象,通常要考虑其拥有的属性,管理其内部状态并暴露行为。有些领域中的动作看上去不属于任何对象,它们代表了领域中的重要行为,所以不能忽略它们或者把它们合并到某个实体或值对象中。通常这样的行为会跨多个对象。当这样的行为从领域中被识别出来时,最佳方式是将其声明成一个服务,服务实现不属于实体和值对象的业务逻辑对象。