DDD学习第一讲-入门基础概念

目录

一、领域驱动设计

领域和子域

核心域、通用域和支撑域

通用语言、限界上下文

实体和值对象

聚合和聚合根

领域事件

二、贫血和充血模型

三、领域模型设计一般步骤


一、领域驱动设计

领域驱动设计(DDD),它是针对复杂系统设计的⼀一套整软件⼯工程⽅方法。

DDD 是一种处理高度复杂领域的设计思想,它试图分离技术实现的复杂性,并围绕业务概念构建领域模型来控制业务的复杂性,以解决软件难以理解,难以演进的问题。DDD 不是架构,而是一种架构设计方法论,它通过边界划分将复杂业务领域简单化,帮我们设计出清晰的领域和应用边界,可以很容易地实现架构演进。

DDD 的知识体系提出了很多的名词,像:领域子域核心域通用域支撑域限界上下文聚合聚合根实体值对象等等

 

Eg:商品领域

 

领域和子域

百度百科对领域的解释:“领域具体指一种特定的范围或区域。”,领域就是用来确定范围的,范围即边界,这也是 DDD 在设计中不断强调边界的原因。

在研究和解决业务问题时,DDD 会按照一定的规则将业务领域进行细分,当领域细分到一定的程度后,DDD 会将问题范围限定在特定的边界内,在这个边界内建立领域模型,进而用代码实现该领域模型,解决相应的业务问题。简言之,DDD 的领域就是这个边界内要解决的业务问题域。

既然领域是用来限定业务边界和范围的,那么就会有大小之分,领域越大,业务范围就越大,反之则相反。

领域可以进一步划分为子领域。我们把划分出来的多个子领域称为子域,每个子域对应一个更小的问题域或更小的业务范围。

领域建模和微服务建设的过程和方法基本类似,其核心思想就是将问题域逐步分解,降低业务理解和系统实现的复杂度。

第一步确定研究对象,比如我们的研究领域是商品(后续都以商品领域做为例子),那么商品、类目、属性、品牌、库存等都是子域

核心域、通用域和支撑域

子域可以根据自身重要性和功能属性划分为三类子域,它们分别是:核心域、通用域和支撑域。

决定产品和公司核心竞争力的子域是核心域,它是业务成功的主要因素和公司的核心竞争力。没有太多个性化的诉求,同时被多个子域使用的通用功能子域是通用域。还有一种功能子域是必需的,但既不包含决定产品和公司核心竞争力的功能,也不包含通用功能的子域,它就是支撑域。

eg:在商品领域里,商品就是我们的核心域,品牌和库存等都属于通用域,类目就是支撑域。

通用语言、限界上下文

通用语言定义上下文含义,限界上下文则定义领域边界,以确保每个上下文含义在它特定的边界内都具有唯一的含义,领域模型则存在于这个边界之内。

在事件风暴过程中,通过团队交流达成共识的,能够简单、清晰、准确描述业务涵义和规则的语言就是通用语言。

我们知道语言都有它的语义环境,同样,通用语言也有它的上下文环境。为了避免同样的概念或语义在不同的上下文环境中产生歧义,DDD 在战略设计上提出了“限界上下文”这个概念,用来确定语义所在的领域边界。

我们可以将限界上下文拆解为两个词:限界和上下文。限界就是领域的边界,而上下文则是语义环境。通过领域的限界上下文,我们就可以在统一的领域边界内用统一的语言进行交流。

综合一下,我认为限界上下文的定义就是:用来封装通用语言和领域对象,提供上下文环境,保证在领域之内的一些术语、业务相关对象等(通用语言)有一个确切的含义,没有二义性。这个边界定义了模型的适用范围,使团队所有成员能够明确地知道什么应该在模型中实现,什么不应该在模型中实现。

正如电商领域的商品一样,商品在不同的阶段有不同的术语,在销售阶段是商品,而在运输阶段则变成了货物。同样的一个东西,由于业务领域的不同,赋予了这些术语不同的涵义和职责边界,这个边界就可能会成为未来微服务设计的边界。领域边界就是通过限界上下文来定义的。

在我们的电商领域,平台SPU的含义是“末级类目+关键属性+品牌属性”,商品的含义是“平台SPU+商家+营销属性”,SKU的含义是商品+销售属性+库存+价格。

诸如平台SPU、商品、SKU等名词就是我们经过事件风暴达成共识的通用语言,在商品子域下是没有二义性的,但是脱离了商品子域可能含义完全不同。

比如品牌(或属性),在商品子域下表示的商品的品牌(创建/编辑商品选择过的品牌),脱了了商品子域,在品牌子域或者属性子域,品牌完全独立于商品存在,技术实现上品牌表也不应该有任何商品相关的信息。

实体和值对象

实体和值对象是组成领域模型的基础单元。

实体:在 DDD 中有这样一类对象,它们拥有唯一标识符,且标识符在历经各种状态变更后仍能保持一致。对这些对象而言,重要的不是其属性,而是其延续性和标识,对象的延续性和标识会跨越甚至超出软件的生命周期。我们把这样的对象称为实体。

值对象:我们先看一下《实现领域驱动设计》一书中对值对象的定义:通过对象属性值来识别的对象,它将多个相关属性组合为一个概念整体。在 DDD 中用来描述领域的特定方面,并且是一个没有标识符的对象,叫作值对象。简单来说,值对象本质上就是一个集。

本质上,实体是看得到、摸得着的实实在在的业务对象,实体具有业务属性、业务行为和业务逻辑。而值对象只是若干个属性的集合,只有数据初始化操作和有限的不涉及修改数据的行为,基本不包含业务逻辑。

在代码模型中,实体的表现形式是实体类,这个类包含了实体的属性和方法,通过这些方法实现实体自身的业务逻辑。在 DDD 里,这些实体类通常采用充血模型,与这个实体相关的所有业务逻辑都在实体类的方法中实现,跨多个实体的领域逻辑则在领域服务中实现。

值对象在代码中有这样两种形态。如果值对象是单一属性,则直接定义为实体类的属性;如果值对象是属性集合,则把它设计为 Class 类,Class 将具有整体概念的多个属性归集到属性集合,这样的值对象没有 ID,会被实体整体引用

同样的对象在不同的场景下,可能会设计出不同的结果。有些场景中,地址会被某一实体引用,它只承担描述实体的作用,并且它的值只能整体替换,这时候你就可以将地址设计为值对象,比如收货地址。而在某些业务场景中,地址会被经常修改,地址是作为一个独立对象存在的,这时候它应该设计为实体,比如行政区划中的地址信息维护。

在商品核心域,商品(代码中Product类)就应该是一个实体,它是一个有唯一标示的业务对象,包含一些业务行为或业务逻辑,比如商品创建、编辑、上下架等(在充血模型中,这些业务逻辑都在实体内)。

但是商品实体上的商家信息、品牌信息等就是值对象,本质上是一个信息集合,但如果换在商家子域或品牌子域,商家信息和品牌信息就应该有相对应的实体。

聚合和聚合根

领域模型内的实体和值对象就好比个体,而能让实体和值对象协同工作的组织就是聚合,它用来确保这些领域对象在实现共同的业务逻辑时,能保证数据的一致性。

聚合就是由业务和逻辑紧密关联的实体和值对象组合而成的,聚合是数据修改和持久化的基本单元,每一个聚合对应一个仓储,实现数据的持久化。聚合有一个聚合根和上下文边界,这个边界根据业务单一职责和高内聚原则,定义了聚合内部应该包含哪些实体和值对象,而聚合之间的边界是松耦合的。

聚合在 DDD 分层架构里属于领域层,领域层包含了多个聚合,共同实现核心业务逻辑。聚合内实体以充血模型实现个体业务能力,以及业务逻辑的高内聚。跨多个实体的业务逻辑通过领域服务来实现,跨多个聚合的业务逻辑通过应用服务来实现。

聚合根的主要目的是为了避免由于复杂数据模型缺少统一的业务规则控制,而导致聚合、实体之间数据不一致性的问题。

如果把聚合比作组织,那聚合根就是这个组织的负责人。聚合根也称为根实体,它不仅是实体,还是聚合的管理者。

聚合的一些设计原则

  • 在一致性边界内建模真正的不变条件

  • 设计小聚合

  • 通过唯一标识引用其它聚合

  • 在边界之外使用最终一致性

  • 通过应用层实现跨聚合的服务调用

再以商品子域为例,商品实体 + 商品销售属性(值对象) + 商品营销属性(值对象) + 商品类目(值对象) + 商家信息(值对象)等成为一个聚合,这个聚合的聚合根就是商品实体。

SKU实体 + SKU销售属性(值对象) + SKU库存(值对象) 等成为一个聚合,这个聚合的聚合根就是SKU实体。

领域事件

在事件风暴(Event Storming)时,我们发现除了命令和操作等业务行为以外,还有一种非常重要的事件,这种事件发生后通常会导致进一步的业务操作,在 DDD 中这种事件被称为领域事件。

领域事件是领域模型中非常重要的一部分,用来表示领域中发生的事件。一个领域事件将导致进一步的业务操作,在实现业务解耦的同时,还有助于形成完整的业务闭环。

领域事件驱动设计可以切断领域模型之间的强依赖关系,事件发布完成后,发布方不必关心后续订阅方事件处理是否成功,这样可以实现领域模型的解耦,维护领域模型的独立性和数据的一致性。在领域模型映射到微服务系统架构时,领域事件可以解耦微服务,微服务之间的数据不必要求强一致性,而是基于事件的最终一致性。

比如在商家领域,进行了下线商家操作,将会导致商品领域下架这个商家所有的商品,那么下线商家就是一个领域事件。

二、贫血和充血模型

失血模型:是指使用的领域对象中只有setter和getter方法,所有的业务逻辑都不包含在领域对象中而是放在业务逻辑层

贫血模型:模型包含了不依赖于持久化的原子领域逻辑,而组合逻辑在Service层。

充血模型:将大多数业务逻辑放在领域实体中实现,实体本身包含了属性和它的业务行为,它在领域模型中就是一个具有业务行为和逻辑的基本业务单元。

三、领域模型设计一般步骤

  1. 根据需求划分出初步的领域和限界上下文,以及上下文之间的关系;

  2. 进一步分析每个上下文内部,识别出哪些是实体,哪些是值对象;

  3. 对实体、值对象进行关联和聚合,划分出聚合的范畴和聚合根;

  4. 为聚合根设计仓储,并思考实体或值对象的创建方式;

  5. 在工程中实践领域模型,并在实践中检验模型的合理性,倒推模型中不足的地方并重构。

参考文档

DDD书籍推荐

阿里技术专家详解 DDD 系列

极客时间课程

DDD实践项目

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值