DDD的核心思想

通过领域驱动设计方法定义领域模型,从而确定业务和应用边界,保证业务模型和代码模型的一致性

三步划定领域模型和微服务的边界


第一步:在事件风暴中梳理业务过程中的用户操作、事件以及外部依赖关系、根据这些要素梳理出领域实体等领域对象

第二步:根据领域实体之间的业务关联性,将业务紧密相关的实体进行组合形成的聚合,同时确定聚合中的聚合根、值对象和实体。在这个图里,聚合之间的边界是第一层边界,它们在同一个微服务实例中运行,这个边界是逻辑边界

第三步:根据业务及语义边界等因素,将一个或者多个聚合划定在一个界限上下文内,形成领域模型。在这个图里,限界上下文是第二层边界,这一层 边界可能就是未来微服务的边界,不同限界上下文的领域逻辑被隔离在不同的微服务实例中运行,物理上相互隔离,所以是物理边界

实体和值对象

**实体的理解:**是一个具体的类对象,它们拥有唯一标识符(ID),且标识符在历经各种状态变更后仍能保持一致
**值对象的理解:**通过对象属性值来识别的对象,它将多个相关属性组合为一个概念整体(没有唯一标识符)

实体的业务形态

领域模型中的实体是多个属性、操作或行为的载体
在事件风暴中,我们可以根据命令、操作或者事件,找出产生这些行为的业务实体对象,进而按照一定的业务规则将依存度和业务紧密关联的对个实体对象和值对象进行聚类,形成聚合
实体和值对象是组成领域模型的基础单元

实体的代码形态

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

实体的运行形态

实体以DO(领域对象)的形式存在,每个实体对象都有唯一的id
可以对一个实体对象进行多次修改,修改后的数据和原来的数据可能会大不相同。但是,由于它们拥有相同的id,它们依然是同一个实体

实体的数据库形态

与传统数据模型设计优先不同,DDD是先构建领域模型,针对实际业务场景构架实体对象和行为,再将实体对象映射到数据持久化对象

  • 在领域模型映射到数据模型时,一个实体可能对应0个、1个或者多个数据库持久对象大多数情况下实体和持久化对象是一对一
    在某些场景中,有些实体只是暂驻静态内存的一个运行态实体,它不需要持久化。比如,基于多个价格配置数据计算后生成的折扣实体。
  • 在有些复杂场景下,实体与持久化对象则可能是一对多或者多对一的关系。比如,用户 user 与角色 role 两个持久化对象可生成权限实体,一个实体对应两个持久化对象,这是一对多的场景。
  • 有些场景为了避免数据库的联表查询,提升系统性能,会将客户信息 customer 和账户信息 account 两类数据保存到同一张数据库表中,客户和账户两个实体可根据需要从一个持久化对象中生成,这就是多对一的场景。

值对象的业务形态

本质上,实体是看得到、摸得着的实实在在的业务对象,实体具有业务属性、业务行为和业务逻辑。

而值对象只是若干个属性的集合,只有数据初始化操作和有限的不涉及修改数据的行为,基本不包含业务逻辑。在逻辑上它仍然是实体属性的一部分,用于描述实体的特征。

值对象中也有部分共享的标准类型的值对象,它们有自己的限界上下文,有自己的持久化对象,可以建立共享的数据类微服务,比如数据字典。

值对象的代码形态

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

值对象的运行形态

实体实例化后的 DO 对象的业务属性和业务行为非常丰富,但值对象实例化的对象则相对简单和乏味。除了值对象数据初始化和整体替换的行为外,其它业务行为就很少了。

值对象嵌入到实体的话,有这样两种不同的数据格式,也可以说是两种方式,分别是属性嵌入的方式和序列化大对象的方式。

  • 引用单一属性的值对象或只有一条记录的多属性值对象的实体,可以采用属性嵌入的方式嵌入。以上面的代码为例:

  • 引用一条或多条记录的多属性值对象的实体,可以采用序列化大对象的方式嵌入。以上面的代码为例:

值对象的数据库形态

DDD 引入值对象是希望实现从“数据建模为中心”向“领域建模为中心”转变,减少数据库表的数量和表与表之间复杂的依赖关系,尽可能地简化数据库设计,提升数据库性能。

值对象在数据库持久化方面简化了设计,它的数据库设计大多采用非数据库范式,值对象的属性值和实体对象的属性值保存在同一个数据库实体表中。

在这块建议的具体做法是:

  • 在领域建模时,我们可以将部分对象设计为值对象,保留对象的业务涵义,同时又减少了实体的数量;
  • 在数据建模时,我们可以将值对象嵌入实体,减少实体表的数量,简化数据库设计。

以上面的代码为例,在领域建模时,我们可以把地址作为值对象,人员作为实体,这样就可以保留地址的业务涵义和概念完整性。而在数据建模时,我们可以将地址的属性值嵌入人员实体数据库表中,只创建人员数据库表。

值对象的优势和局限

值对象采用序列化大对象的方法简化了数据库设计,减少了实体表的数量,可以简单、清晰地表达业务概念。

这种设计方式虽然降低了数据库设计的复杂度,但却无法满足基于值对象的快速查询,会导致搜索值对象属性值变得异常困难。

值对象采用属性嵌入的方法提升了数据库的性能,但如果实体引用的值对象过多,则会导致实体堆积一堆缺乏概念完整性的属性,这样值对象就会失去业务涵义,操作起来也不方便。

在使用时要充分的考虑值对象的优缺点。

实体与值对象关系的理解

理解和分析聚合思想:聚合和聚合根

在事件风暴中,我们会根据一些业务操作和行为找出实体或值对象,进而将业务关联紧密的实体和值对象进行组合,构成聚合,再根据业务语义将多个聚合划定到同一个限界上下文中,并在限界上下文完成领域建模

对聚合的理解

聚合就是由业务和逻辑机密关联的实体和值对象组合而成的,聚合是数据修改后和持久化的基本单元,每一个聚合对应一个仓储,实现数据的持久化
聚合有一个聚合根和上下文边界,这个边界根据业务单一职责和高内聚原则,定义了聚合内部应该包含哪些实体和值对象,而聚合之间的边界是松耦合的
聚合在DDD分层架构中属于领域层,领域层包含了多个聚合,共同实现核心业务逻辑
聚合内实体以充血模型实现个体业务能力,以及业务逻辑的高内聚。跨多个实体的业务逻辑通过领域服务来实现,跨多个聚合的业务逻辑通过应用服务来实现

对聚合根的理解和分析

聚合根的主要目的是为了避免由于复杂数据模型缺少统一的业务规则控制,而导致聚合,实体之间数据不一致性的问题
如果把聚合比作组织,那聚合根就是这个组织的负责人.聚合根也称为根实体,它不仅是实体,还是聚合的管理者

  • 首先它作为实体本身,拥有实体的属性和业务行为,实现自身而定业务逻辑
  • 其次它作为聚合的管理者,在聚合内部负责协调实体和值对象按照固定的业务规则协同完成共同的业务逻辑
  • 最后在聚合之间,他还是聚合对外的接口人,以聚合根Id关联的方式接受外部任务和请求,在上下文实现聚合之间的业务协同

聚合、聚合根、实体、值对象的对比

聚合 高内聚、低耦合,它是领域模型中最底层的边界,可以作为拆分微服务的最小单位,但不建议你对微服务过度拆分。
在对性能有极致要求的场景中,聚合可以独立作为一个微服务,以满足版本的高频发布和极致的弹性伸缩能力。
一个微服务可以包含多个聚合,聚合之间的边界是微服务内天然的逻辑边界。
聚合根 聚合根是实体,有实体的特点,具有全局唯一标识,有独立的生命周期。
一个聚合只有一个聚合根,聚合根在聚合内对实体和值对象采用直接对象引用的方式进行组织和协调,聚合根与聚合根之间通过id关联的方式实现聚合之间的协同
实体 有id标识,通过id判断相等性,id在聚合内唯一
状态可变,它依附于聚合根,其生命周期由聚合根管理
实体一般会持久化,但与数据库持久化对象不一定是一对一关系
实体可以引用聚合内的聚合根、实体和值对象
值对象 无id、不可变、无生命周期、用完即扔
值对象之间通过属性值判断相等性
核心本质是值,是一组概念完整的属性组成的集合,用于描述实体的状态和特征
值对象尽量只引用值对象

DDD:领域驱动设计相关推荐

  1. DDD领域驱动设计之聚合、实体、值对象

    关于具体需求,请看前面的博文:DDD领域驱动设计实践篇之如何提取模型,下面是具体的实体.聚合.值对象的代码,不想多说什么是实体.聚合等概念,相信理论的东西大家已经知晓了.本人对DDD表示好奇,没有在真 ...

  2. DDD领域驱动设计 — 贫血模型与充血模型

    文章转载来源:https://juejin.cn/post/6917125801460629518 | 前言  要想深入掌握和了解 DDD 领域驱动设计的核心,那无论如何也绕不开两大较为抽象的概念-- ...

  3. DDD 领域驱动设计:贫血模型、充血模型的深入解读!

    作者:JavaEdge在掘金 链接:https://juejin.cn/post/6917125801460629518 -     前言     - 要想深入掌握和了解 DDD 领域驱动设计的核心, ...

  4. 浅谈我对DDD领域驱动设计的理解

    从遇到问题开始 当人们要做一个软件系统时,一般总是因为遇到了什么问题,然后希望通过一个软件系统来解决. 比如,我是一家企业,然后我觉得我现在线下销售自己的产品还不够,我希望能够在线上也能销售自己的产品 ...

  5. C#进阶系列——DDD领域驱动设计初探(五):AutoMapper使用

    前言:前篇搭建了下WCF的代码,就提到了DTO的概念,对于为什么要有这么一个DTO的对象,上章可能对于这点不太详尽,在此不厌其烦再来提提它的作用: 从安全上面考虑,领域Model都带有领域业务,让Cl ...

  6. DDD 领域驱动设计:贫血模型、充血模型的深入解读

    点击上方"朱小厮的博客",选择"设为星标" 后台回复"书",获取 后台回复"k8s",可领取k8s资料 -     前言 ...

  7. [转]浅析DDD(领域驱动设计)

    最近在做一些微服务相关的设计,内容包括服务的划分,Restful API的设计等.其中比较棘手的就是Service的职责划分:如何抽象具有统一业务范畴的Model,使其模块化,又如何高度提炼并组合多模 ...

  8. 浅析DDD(领域驱动设计)

    最近在做一些微服务相关的设计,内容包括服务的划分,Restful API的设计等.其中比较棘手的就是Service的职责划分:如何抽象具有统一业务范畴的Model,使其模块化,又如何高度提炼并组合多模 ...

  9. DDD 领域驱动设计落地实践:六步拆解 DDD

    引言 相信通过前面几篇文章的介绍,大家对于 DDD 的相关理论以及实践的套路有了一定的理解,但是理解 DDD 理论和实践手段是一回事,能不能把这些理论知识实际应用到我们实际工作中又是另外一回事,因此本 ...

  10. DDD 领域驱动设计-三个问题思考实体和值对象(续)

    上一篇:DDD 领域驱动设计-三个问题思考实体和值对象 说实话,整理现在这一篇博文的想法,在上一篇发布出来的时候就有了,但到现在才动起笔来,而且写之前又反复读了上一篇博文的内容及评论,然后去收集资料, ...

最新文章

  1. 基于SSM的餐饮工业化管理系统-计算机毕业设计
  2. 平流式初沉池贮砂斗计算_?初沉池、二沉池的作用与区别-亨孚科技
  3. Linux as 5 下部署oracle 10.2.0.1(2)
  4. 手游复古传奇服务器维护,复古传奇手游:服务器中那些极品装备,属性也是逆天!...
  5. Jenkins插件开发(四)-- 插件发布
  6. Xcode 5中缺少Provisioning Profiles菜单项
  7. Java类权限和类成员权限举例解析
  8. 关于Protel 2004 绘制电路原理图
  9. python怎么判断实数_检查python对象是否可以解释为实数[python]
  10. Service Mesh中的通用数据平面API设计
  11. liunx系统下搭建domian
  12. FTP连接时出现“227 Entering Passive Mode” 的解决方法(附加实际案例)
  13. 霹雳吧啦wz学习笔记1_卷积神经网络
  14. gta5的服务器状态,Gta5OL一直处于加载过程中,你可能遇到了这些问题
  15. 云平台与云管平台,你分得清吗?
  16. keil加入文件夹软件崩溃解决办法
  17. WPS表格中使用SQL语句获取动态列
  18. Fitnesse初体验(介绍、下载、安装)
  19. 南潮科技:还原工业级智能网关的开发过程
  20. 震源机制(Focal Mechanism)之断层基本知识

热门文章

  1. 运维监控系列(15)-Alertmanager添加163邮箱、钉钉、微信告警通知功能
  2. 复制指定目录后缀文件并重命名
  3. Python将指定文件批量复制到多个文件夹并重命名
  4. Day74~75_Flink(一)Flink基础核心知识
  5. 通过CSS写提示工具栏的上下左右箭头
  6. 生日祝福html_集体生日会|生活明朗,万物可爱,我们一起长大
  7. 我们该如何运营Facebook账号呢?
  8. alibabaprotect 是危险的有害的顽固的病毒般的存在
  9. Html上传文件php处理上传文件
  10. JS如何获取指定元素下的子元素的值