解析DDD中的聚合对象

对象这个词对我们而言并不陌生。以最常见的面向对象为例,软件系统中的任何事物都被认为是一种对象。而针对如何设计和实现这些对象,也存在一批开发模式。例如,一种传统的做法是从数据的角度来规划对象的组织形式,先设计数据库模型,然后基于数据库模型设计对象,这些对象内部通常只包含数据属性的定义,也就是说整个开发过程是数据驱动(Data Driven)的。


随着DDD思想和方法日渐深入人心。我们认为数据驱动并不是一种理想的对象设计方法,取而代之的应该采用领域驱动(Domain Driven)的方法来设计系统中的对象。为此,DDD专门引入了一个全新的对象,即聚合(Aggregate)对象。那么:

  1. 什么是聚合对象?
  2. 如何设计聚合对象?

这就是我们今天要讨论的内容。

什么是聚合对象?

在DDD中,对象的设计过程是领域驱动(Domain Driven)的,这与数据驱动完全不同。这些领域模型对象内部不仅仅只定义了数据属性,而更多包含了业务逻辑的处理过程。下图展示了数据对象与领域模型对象的这种差异。


和限界上下文被用来划分子域之间的业务边界一样,在领域模型对象中,我们也需要从软件复杂度的角度出发,明确对象之间的边界。现在,假设系统中存在8个对象,那么它们的一种交互方式如下图所示。


从上图中可以看出,原则上这8个对象之间的交互方式最多可以达到28-1次。而一个系统中的对象显然远远不止这个数量级,系统的复杂度会随着对象数量的增多而急剧上升,这也是架构腐化的一个根源。为了降低这种对象交互所带来的复杂度,DDD引入了聚合对象的概念。那么,聚合是如何来做到这一点的呢?

聚合的设计思想实际上很简单,就是尽量减少系统中对象之间的关联关系,简化外部组件对领域模型对象的访问入口,从而降低系统的复杂度。

现在,我们已经明确了DDD中聚合的设计思想,接下来我们来讨论它的组成结构。聚合有两部分组成,分别是聚合根和聚合边界。

  1. 聚合根:聚合对外暴露的访问对象,外部组件只能通过这个聚合根对象实现对聚合的修改和更新
  2. 聚合边界:聚合的业务边界和范围,规定了一个聚合内部应该具备哪些业务逻辑和操作


换句话说,对于一个聚合而言,外部组件只能看到一个聚合根对象,而位于聚合边界内部的其他对象只能通过聚合根进行关联,这种关联操作包括对对象的创建、查询、更新和删除。通过这种固定的规则,我们也确保聚合内部的数据操作具有严格的事务性。我们回到前面讨论的案例,基于聚合思想就可以得到如下图所示的效果图。


可以看到,我们把原本8个对象拆分成了3个聚合对象,每个聚合对象又一个明确的边界,内部包含了一定数量的领域模型对象。而这3个聚合对象之间的交互只能通过各自的聚合根。这样,对象之间的最多交互次数就变成了23-1次,而不是原本的28-1次。

如何设计聚合对象?

现在,我们已经回答了“什么是聚合对象?”这一核心问题。接下来讨论今天的第二个问题,即如何设计聚合对象?

事实上,在DDD中,领域模型对象包括三大类。除了聚合对象之外,还包括实体(Entity)和值对象(Value Object)。


在这三种领域模型对象中,聚合是核心。实体和值对象是聚合的组成部分,而值对象同时也是实体的组成部分,这三种对象之间的组成关系如下图所示。


接下来,我们先从实体对象开始讲起。实体对象是构成聚合对象的基础。事实上,聚合中的聚合根就是一种实体对象。

实体

实体对象和数据对象的区别在于,实体中除了定义了数据属性之外,还包含了业务的状态以及围绕这些状态所产生的生命周期,也就是说它具有可变性。同时,我们也需要使用唯一标识来区分不同的实体对象,也就是说它具有唯一性。


唯一标识(Identity)是实体对象必须具备的一种属性,也是实体与值对象之间核心区别之一。实体对象的唯一标识概念比较好理解,实现起来方法也有很多。而所谓的可变性,指的是实体对象一般都会具备自己的基础业务方法,同时对自身对象的生命周期进行统一的管理和维护。下图展示了一个典型的实体对象的表现形式,这个对象来自于客户系统中的工单管理场景。


值对象

值对象的特征决定了如何分离值对象的方法。与实体对象相比,值对象自身没有状态,所以是一种不可变对象。在设计过程中,通常我们会先识别系统中的实体对象,然后从实体对象中分离出潜在的值对象。下图给出了实现这一过程的一个示例。

 

在上图中,我们首先设计了一个订单对象Order,显然该对象具有唯一标识符orderNumber,所以是一个实体对象。然后我们发现Order对象中包含了收货地址DeliveryAddress,而DeliveryAddress就可以被抽取成一个值对象。因为对于一个收货地址而言,可以被多个订单所共用,不需要具备唯一标识,而且也没有可变性。如果我们需要改变收货地址,通常是新生成一个DeliveryAddress对象。

聚合

介绍完实体和值对象之后,我们通过一个典型的案例来解释聚合建模的实现过程。在日常开发过程中,我们通常都需要对业务功能(Feature)进行评审,然后通过拆分任务(Task)的方式完成工作量评估和排期(Schedule)。在这个业务场景中,一个业务功能可以创建很多任务,同时需要评估出一个排期。通过分析,我们可以识别Feature、Task、Schedule这三个领域模型对象。

那么,如何基于这三个领域模型对象开展聚合设计工作呢?我们有三条基本原则。

  1. 关注聚合内部真正的不变条件
  2. 设计小聚合
  3. 通过唯一标识引用其他聚合

基于以上三条设计原则,我们可以通过下图完成对上述场景的聚合建模。


可以看到,这里我们把Feature和Task设计为聚合对象,并通过两个值对象分别指定他们的唯一标识,而把Plan设计成一个实体对象。

如果你正在开发一个DDD应用程序,那么识别系统中的聚合对象并完成对其的建模是一项必不可少的工作。针对系统中的每一个子域以及上下文边界,我们首先对系统中存储的各种对象进行区分,在实体、值对象的集成上抽象聚合概念,确保边界的完整性和对象访问有效性。

聚合建模方法需要考虑业务场景和需求上下文,有时候并没有标准的设计方案,而是取决于你对业务模型的理解和分析。今天的内容针对聚合的设计思想以及表现形式进行了详细的分析,帮助你更好的把它应用到日常开发过程中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3248117.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

甲骨文面试题【动态规划】力扣377.组合总和IV

给你一个由 不同 整数组成的数组 nums ,和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。 题目数据保证答案符合 32 位整数范围。 示例 1: 输入:nums [1,2,3], target 4 输出:7 解释&#x…

QTableView仿Excel表头排序和筛选

一.效果 Excel的排序和筛选弹窗如下所示 功能非常强大。不仅支持内容排序和筛选,还支持颜色的排序和筛选,而且还支持设置多种过滤条件。本文只仿最常用的内容排序和内容单过滤条件的筛选,效果如下所示。 从效果图中可以看出,表头Section中的按钮有下列六种状态 enum Butt…

Redis 教程:从入门到入坑

目录 1. Redis 安装与启动1.1. 安装 Redis1.1.1. 在Linux上安装1.1.2. 在Windows上安装 1.2. 启动 Redis1.2.1. 在Linux上启动1.2.2. 在Windows上启动 1.3. 连接Redis1.3.1. 连接本地Redis1.3.2. 连接远程Redis1.3.2.1. 服务器开放端口1.3.2.2. 关闭防火墙1.3.2.3. 修改配置文件…

GESP CCF C++ 三级认证真题 2024年6月

第 1 题 小杨父母带他到某培训机构给他报名参加CCF组织的GESP认证考试的第1级,那他可以选择的认证语言有()种。 A. 1 B. 2 C. 3 D. 4 第 2 题 下面流程图在yr输入2024时,可以判定yr代表闰年,并输出 2月是29天 &#x…

【整体介绍】HTML和JS编写多用户VR应用程序的框架

一、Networked-Aframe是什么? 简称NAF,底层基于Mozilla的AFrame框架,用HTML和JS编写多用户VR应用程序的框架。 二、特性 支持 WebRTC 和/或 WebSocket 连接。 语音聊天。音频流让您的用户在应用程序内交谈(仅限 WebRTC&#xff…

AV1技术学习: Compound Prediction

一、双向 Compound Prediction AV1支持两个参考帧的预测通过多种复合模式线性组合。复合预测公式为 其中,权重m(x, y) is scaled by 64 以进行整数计算,R1(x, y)和R2(x, y)表示两个参考块中位于(x, y)的像素。P(x, y)将按比例缩小 1/64 以形成最终的预测…

Android安卓使用MQTT(JAVA)

一、app目录下添加 implementation org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0 1) 点击Sync Now更新依赖 2) AndroidManifest.xml文件添加网络权限 <uses-permission android:name"android.permission.INTERNET"/> 二、 使用 1) 创建MqttConn…

使用 ABBYY FineReader PDF 15 在创建或转换 PDF 时自动生成书签

使用 ABBYY 为 PDF 文件添加书签&#xff0c;可以帮助快速定位文档中的主要内容&#xff0c;也能更方便的梳理出一份文档大纲。 有很多 PDF 文件在创建时并没有编辑书签&#xff0c;这里介绍使用 ABBYY FineReader PDF 15&#xff08;Win 系统&#xff09;在 PDF 中自动添加书…

postMessageXss续2

原文地址如下:https://research.securitum.com/art-of-bug-bounty-a-way-from-js-file-analysis-to-xss/ 在19年我写了一篇文章&#xff0c;是基于postMessageXss漏洞的入门教学:https://www.cnblogs.com/piaomiaohongchen/p/14727871.html 这几天浏览mXss技术的时候&#xff…

第三周周三总结

1.给你一个 32 位的有符号整数 x &#xff0c;返回将 x 中的数字部分反转后的结果。 如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] &#xff0c;就返回 0。 假设环境不允许存储 64 位整数&#xff08;有符号或无符号&#xff09;。 示例 1&#xff1a; 输…

RuoYi-后端管理项目入门篇1

目录 前提准备 下载若依前后端 Gitee 地址 准备环境 后端数据库导入 1 克隆完成 若依后端管理后端 Gitte 地址 :若依/RuoYi-Vue 2.1 创建Data Source数据源 2.2 填写好对应的数据库User 和 Password 点击Apply 2.3 新建一个Schema 2.4 填写对应数据库名称 这边演示写的…

【I²C协议】STC89C51单片机IIC通信(代码+原理)

STC89C51单片机IIC通信 什么是IC协议特点构成 通信协议开始信号、结束信号、应答信号数据传输 代码示例 什么是IC协议 IIC,即IC&#xff0c;全称 Inter-Integrated Circuit&#xff0c;字面上的意思是集成电路之间&#xff0c;它其实是IC Bus简称&#xff0c;所以中文应该叫 集…

【Codeforces】Round 957 (Div. 3)_B. Angry Monk

作者&#xff1a;指针不指南吗 专栏&#xff1a;算法刷题 &#x1f43e;或许会很慢&#xff0c;但是不可以停下来&#x1f43e; 文章目录 题目题解try1代码正确题解贪心策略的解释为什么不是直接合并 总结 题目 题目链接 题解 try1代码 我的思路&#xff1a;单纯模拟 循环&a…

【字幕】字幕特效入门

前言 最近两周调研了一下字幕特效的底层程序逻辑&#xff0c;因为工作内容的原因&#xff0c;就分享几个自己找的链接具体细节就不分享了&#xff0c;CSDN也是我的个人笔记&#xff0c;只记录一些简单的内容用于后续自己方便查询&#xff0c;顺便帮助一下正在苦苦查阅资料入门…

基于STC89C51单片机的烟雾报警器设计(煤气火灾检测报警)(含文档、源码与proteus仿真,以及系统详细介绍)

本篇文章论述的是基于STC89C51单片机的烟雾报警器设计的详情介绍&#xff0c;如果对您有帮助的话&#xff0c;还请关注一下哦&#xff0c;如果有资源方面的需要可以联系我。 目录 摘要 原理图 实物图 仿真图 元件清单 代码 系统论文 资源下载 摘要 随着现代家庭用火、…

【高中数学/指数函数、幂函数】寻找曲线y=2^x与y=x^2的三个交汇点

【问题】 找到曲线y2^x与yx^2的三个交汇点。 【难点】 指数和二次函数摆在一起没法求解。 【解答】 y2^x与yx^2的交汇点&#xff0c;即曲线y2^x-x^2的零点&#xff0c;用Canvas作图就能清晰看到三个零点的存在&#xff0c;如图。 【图一】 其中&#xff0c;2&#xff0c;…

自制连点器

B站使用教程&#xff1a;https://www.bilibili.com/video/BV1SR85e4EKw/?vd_source47eba1800d831e86d4778a128740fe73 下载链接&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1Spv_yVPFB3zoS__VL-nhaQ?pwdyxo1 提取码&#xff1a;yxo1

排序算法(4)之快速排序(1)

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 排序算法(4)之快速排序(1) 收录于专栏【数据结构初阶】 本专栏旨在分享学习数据结构学习的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目…

langchain循序渐进之langchain 安装及使用

pip安装langchain pip install langchain安装langsmith(可选) langsmith官方提示是用来观察大模型复杂调用情况&#xff0c;可选项。 [LangSmith]点击注册然后把秘钥填进去就行&#xff0c;这里我略过了 export LANGCHAIN_TRACING_V2"true" export LANGCHAIN_A…

【C++】模版初阶以及STL的简介

个人主页~ 模版及STL 一、模版初阶1、泛型编程2、函数模版&#xff08;1&#xff09;概念&#xff08;2&#xff09;函数模版格式&#xff08;3&#xff09;函数模版的原理&#xff08;4&#xff09;函数模版的实例化①显式实例化②隐式实例化 &#xff08;5&#xff09;模版参…