文章目录
- DDD(领域驱动设计) 核心概念浅析
- 前言
- 贫血模型
- 什么是贫血模型
- 贫血模型的优点
- 贫血模型的缺点
- 充血模型
- 充血模型的优点
- 充血模型的缺点
- DP 概念
- 抽象接口
- 简单概念
- 简单概念
- 流程:
- 实现
- 统一语言和模型价值
- DP 和 Entity 的区别
- Aggregate(聚合)
- 限界上下文
- 防腐层(Anti-corruption layer)
- 应用场景
- 解决方案
- 问题
- 总结
DDD(领域驱动设计) 核心概念浅析
前言
大家好,这里是 Rocky 编程日记
,喜欢后端架构
及中间件源码
,该篇是对 DDD(领域驱动设计)
做了一个简短的概念梳理。文章分享出来,供大家学习交流,如若笔记中有不对的地方,那一定是当时我的理解还不够,希望你能及时提出。
贫血模型
什么是贫血模型
在日常项目中,我们也会把大部分的业务逻辑实现都写到 service 层里,而不是写在我们的实体类中。即实体类里面只包含了对象的属性以及属性的 get 、set 方法,不包括该对象的具体行为,业务逻辑都处于 service 层。
贫血模型的优点
将业务逻辑分离了出去,使得系统耦合度降低,对象只用作承载和传输暑假。
贫血模型的缺点
不符合面向对象编程 (OOP) 的思想,对象只有属性没有行为,没有生命,不是真正的对象。
业务逻辑分离到了 service 层,service 层会显得十分厚重。
充血模型
不仅包含了对象的属性,还包含了属性的职责,对象的行为,包括业务逻辑、数据持久化等操作。
充血模型的优点
面向对象,Business Logic符合单一职责,不像在贫血模型里面那样包含所有的业务逻辑太过沉重。
充血模型的缺点
对于如何划分业务逻辑,什么样的逻辑应该放在Domain Object中,什么样的业务逻辑应该放在Business Logic中比较含糊。
DP 概念
在 DDD 里,DP (Domain Primitive) 可以说是一切模型、方法、架构的基础。它是在特定领域、拥有精准定义、可以自我验证、拥有行为的对象。可以认为是领域的最小组成部分。
DP 三条原则
- 让隐性的概念显性化
- 让隐性的上下文显性化
- 封装多对象行为
思考: 在实际的项目中,如果你使用了充血模型,那么如何把握它的强弱程度?
依赖都是可以替换的,属于业务域核心逻辑之外的东西,你对他们是没有控制权的,即使这些外部依赖产生了变动,也能将自身系统产生的变化,控制在最小范围内。
由外部系统的依赖变动,导致的内部系统的改造程度,我们可以理解为一个系统的可维护性。
抽象接口
抽象接口本质是一种中间协议,依赖方和被依赖方都只要对该协议负责,接口将软件分层隔离,在这种隔离下任何一方的变动都将被控制在当前范围内。
M个业务 * N个业务 -> M个业务 + N个业务
由内部逻辑的变化所导致的内部系统的改造程序,我们可以狭义地理解为系统的 可扩展性。
思考:发奖的逻辑如果改动,难道还要修改注册逻辑么?
简单概念
简单概念
● DP:抽象并封装自检和一些隐性属性的计算逻辑,且这些属性是无状态的
● Entity:抽象并封装单对象有状态的逻辑
● Domain Service:抽象并封装多对象的有状态逻辑
● Repository:抽象并封装外部数据访问逻辑。
流程:
- 首先对需要处理的业务问题进行总览。
- 然后领域对象 (Entity) 进行划分,明确每个领域对象的包含的信息和职责边界。并进行跨对象,多对象的逻辑组织(Domain Service)。
- 接着在上层应用中根据业务描述去编排 Entity 和 Domain Service。
- 最后再做一些下水道工作,去对下层的数据访问、RPC调用去做一些具体
实现
DDD语境 | 传统语境 | |
---|---|---|
含义 | ValueObject | ViewObject / ValueObject |
作用 | 领域基础类型 | 用于展示的数据 |
统一语言和模型价值
财务人眼中 | 技术人眼中 | |
---|---|---|
含义 | 资产=负债+所有者权益 | 借钱? 存钱?贷款? |
为了建设有价值的模型,我们需要在形成UL的基础上,消化知识,并向模型中提炼知识。
DP 和 Entity 的区别
DP(VO) | Entity | |
---|---|---|
是否充血 | 是 | 是 |
有无状态 | 无 | 有 |
举例:有无状态的判定即 “程序是否需要追踪该对象的变化事件”,具体来说就是 假如体育场的很多座位,观众通过预定程序买了票,每张票上都对应一个座位号,这种场景下,座位就是有状态的,它是 Entity , 程序需要关注该对象的变化事件,比如通过唯一 ID 来追踪该对象,关注它的预定状态,价格,位置等属性。另一种场景下,假如观众通过预定程序买了票,进场只要有空座位就可以随便坐,这时候,座位就是无状态的, 它是 DP ,程序不需要对每个座位对象加以追踪,只需要关注总数即可。这也是 DP 和 Entity 的异同之处。
为了建立有价值的模型, 在确认了 UL 之后消化领域知识,并向无状态的 DP 和有状态的 Entity 中提炼知识。
在复杂的系统中,对一个对象进行修改,可能会涉及到大量其他关联对象的状态,如何使这些关联的对象始终保持一致,是一个比较复杂的话题。
Aggregate(聚合)
聚合是对存在引用关系的一组对象的封装,它的目的就是屏蔽掉内部对象之间复杂的关联关系,只对外暴露统一接口,关于聚合,我们需要关注它的两个属性,根对象 (root)
和边界 (Boundary)
。
根对象
:是整个聚合中唯一能够被外部引用的对象,也就是说 聚合所暴露的接口只允许操作根对象,根对象是一个 Entity, 因为每个聚合都需要 ID 和状态来区分其他聚合,所以这里也是通过根对象的 ID 来作为整个聚合的 ID。
边界
: 简单来说,聚合的边界就是你判断哪些对象可以被放入当前聚合的条件。
限界上下文
本质是为了解决复杂系统的领域分治问题,这并不仅仅是 DDD 这种架构方式需要面临和处理的问题,其他任何架构方式都需要处理类似问题,领域分治最清晰的方式就是通过拆分成微服务,但拆分成微服务本身也存在边界问题,而且将会增加通信的复杂度,
其次,有些领域能力本身就适合作为一个集合,由一个系统来提供,不适合按照每种能力拆分成微服务,所以在一个系统内,如何进行领域分治,也是一个有价值的话题。
防腐层(Anti-corruption layer)
防腐层(Anti-Corruption Layer)模式,是一种在不同语义的子系统间构建的一层功能,对子系统间的请求进行翻译适配,从而确保应用设计不受外部依赖的系统的限制。
应用场景
许多应用依赖于外部系统提供的数据或者功能。当直接使用外部系统的API、数据结构时,自身就存在因使用外部系统,而被外部系统的质量问题影响,从而“腐化”本身设计的问题。比如,当一个遗留应用需要移植到新系统时,可能仍需使用现存的遗留资源,新的特性需要调用遗留系统。这种场景在系统迁移过程中尤其普遍。
解决方案
在应用自身与外部之间,构筑专门的一层组件或者服务,对两个系统进行通讯转换和语义隔离。这层组件或者服务,称为 防腐层
。
问题
- 防腐层可能增加两个系统间的通讯延迟;
- 防腐层增加了额外的服务,需要管理和维护;
- 如果防腐层是系统迁移战略的一部分,则需要考虑防腐层是否是永久的,是否在遗留系统功能完全迁移完成后将其移除。
总结
大家好,这里是 Rocky 编程日记
,喜欢后端架构
及中间件源码
,该篇是对 DDD(领域驱动设计)
做了一个简短的概念梳理。后面也会陆续分享更多有关于 DDD(领域驱动设计)
的知识,喜欢的小伙伴们可以三连支持一下噢~,同时也可以评论区留下你宝贵的意见噢 ~