DDD实战课
欧创新
人保高级架构师
立即订阅
4865 人已学习
课程目录
已完结 23 讲
0/2登录后,你可以任选2讲全文学习。
开篇词 (1讲)
开篇词 | 学好了DDD,你能做什么?
免费
基础篇 (5讲)
01 | 领域驱动设计:微服务设计为什么要选择DDD?
02 | 领域、子域、核心域、通用域和支撑域:傻傻分不清?
03 | 限界上下文:定义领域边界的利器
04 | 实体和值对象:从领域模型的基础单元看系统设计
05 | 聚合和聚合根:怎样设计聚合?
进阶篇 (6讲)
06 | 领域事件:解耦微服务的关键
07 | DDD分层架构:有效降低层与层之间的依赖
08 | 微服务架构模型:几种常见模型的对比和分析
09 | 中台:数字转型后到底应该共享什么?
10 | DDD、中台和微服务:它们是如何协作的?
答疑:有关3个典型问题的讲解
实战篇 (10讲)
11 | DDD实践:如何用DDD重构中台业务模型?
12 | 领域建模:如何用事件风暴构建领域模型?
13 | 代码模型(上):如何使用DDD设计微服务代码模型?
14 | 代码模型(下):如何保证领域模型与代码模型的一致性?
15 | 边界:微服务的各种边界在架构演进中的作用?
16 | 视图:如何实现服务和数据在微服务各层的协作?
17 | 从后端到前端:微服务后,前端如何设计?
18 | 知识点串讲:基于DDD的微服务设计实例
19 | 总结(一):微服务设计和拆分要坚持哪些原则?
20 | 总结(二):分布式架构关键设计10问
结束语 (1讲)
结束语 | 所谓高手,就是跨过坑和大海!
DDD实战课
登录|注册

04 | 实体和值对象:从领域模型的基础单元看系统设计

欧创新 2019-10-21
你好,我是欧创新。今天我们来学习 DDD 战术设计中的两个重要概念:实体和值对象。
这两个概念都是领域模型中的领域对象。它们在领域模型中起什么作用,战术设计时如何将它们映射到代码和数据模型中去?就是我们这一讲重点要关注的问题。
另外,在战略设计向战术设计过渡的这个过程中,理解和区分实体和值对象在不同阶段的形态是很重要的,毕竟阶段不同,它们的形态也会发生变化,这与我们的设计和代码实现密切相关。
接下来,我们就分别看看实体和值对象的这些问题,从中找找答案。

实体

我们先来看一下实体是什么东西?
在 DDD 中有这样一类对象,它们拥有唯一标识符,且标识符在历经各种状态变更后仍能保持一致。对这些对象而言,重要的不是其属性,而是其延续性和标识,对象的延续性和标识会跨越甚至超出软件的生命周期。我们把这样的对象称为实体。没理解?没关系!请继续阅读。

1. 实体的业务形态

在 DDD 不同的设计过程中,实体的形态是不同的。在战略设计时,实体是领域模型的一个重要对象。领域模型中的实体是多个属性、操作或行为的载体。在事件风暴中,我们可以根据命令、操作或者事件,找出产生这些行为的业务实体对象,进而按照一定的业务规则将依存度高和业务关联紧密的多个实体对象和值对象进行聚类,形成聚合。你可以这么理解,实体和值对象是组成领域模型的基础单元。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《DDD实战课》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(55)

  • 老毕
    陈述一下我的学习心得:实体和值对象的目的都是抽象聚合若干属性以简化设计和沟通,有了这一层抽象,我们在使用人员实体时,不会产生歧义,在引用地址值对象时,不用列举其全部属性,在同一个限界上下文中,大幅降低误解、缩小偏差,两者的区别如下:
    ①两者都经过属性聚类形成,实体有唯一性,值对象没有。在本文案例的限界上下文中,人员有唯一性,一旦某个人员被系统纳入管理,它就被赋予了在事件、流程和操作中被唯一识别的能力,而值对象没有也不必具备唯一性。
    ②实体着重唯一性和延续性,不在意属性的变化,属性全变了,它还是原来那个它;值对象着重描述性,对属性的变化很敏感,属性变了,它就不是那个它了。
    ③战略上的思考框架稳定不变,战术上的模型设计却灵活多变,实体和值对象也有可能随着系统业务关注点的不同而更换位置。比如,如果换一个特殊的限界上下文,这个上下文更关注地址,而不那么关注与这个地址产生联系的人员,那么就应该把地址设计成实体,而把人员设计成值对象。

    作者回复: 你太有才了。理解的很透彻。

    2019-10-21
    6
    56
  • stg609
    我对于实体的看法和老师基本一致,但是值对象有补充,愿讨教。

    首先,值对象没有id的概念,由其所拥有的所有属性来识别,属性值是不可变的。换句话说就是只要两个对象的所有属性都一样那就认为是同一个对象,可以互相替换, 但改变任何一个属性,就是两个不同的对象。

    举个例子,你手里有一张毛爷爷,你不会在意这张毛爷爷是不是之前的那张,你在意的只是它的价值。

    但是一个东西是被建模成值对象还是实体,不是一成不变的。
    举个例子,汽车是一个实体,那车上的引擎可以认为是值对象,对于汽车而言,引擎坏了,换一个一样的就好了。但是对于引擎厂商来说,引擎就是个实体,厂商需要跟踪每个引擎的一些数据变化,不可能这个引擎丢了,随便拿一个新的引擎就可以替代的。

    值对象的好处
    既然是DDD, 从基础设施层,如数据库角度去考虑它的好处感觉有些牵强。我认为还是从如何降低业务复杂性角度出发会更合适。

    ·很容易判断两个对象是否相等
    ·不可变也确保了值对象永远都是正确的,尤其是在并发环境中不会被意外修改,是线程安全的。比如调用 String.ToUpper 会创建一个新的字符串而非修改原来的字符串,这可以避免其他使用了同一字符串的代码出现错误。
    ·值对象既然是不可变的,这使得它天然适合被重用,可以提高性能,就好像很多编程语言中的 String 是不可变的,同样的字符串只占用一份空间。

    所以,鉴于值对象比实体更轻量级,高性能且线程安全,一般建议总是优先建模值对象,而非实体。

    另外,值对象本身虽然是没有id的,但是并不妨碍它的属性是一个实体。

    作者回复: 专业,非常同意你的观点。

    2019-10-29
    2
    8
  • huaweichen
    请问老师,本课程的后面章节,会有关于如何落实DDD的开发实战案例吗?

    作者回复: 会有的,包括事件风暴、从中台的领域建模、到微服务设计都会有案例的,最后会有一个典型案例把这些知识串起来。不过这些案例主要是设计为主,会设计出不同分层的类、服务等,不到具体的代码实现。

    2019-10-21
    4
  • 学到了和以前设计不一样的地方。DDD弱化了数据库设计,减少了表之间的关联关系,将不用来查询的静态值设计为值对象,作为一个字段存储到实体对应的表中。减少了数据库设计的复杂度,避免了复杂的关联。
    教数据库的老师估计想打人了😂

    作者回复: 哈哈,出发点不一样,所以观点会有差异。

    2019-10-22
    2
  • FIGNT
    实体和值对象都是领域模型的成员,实体是业务唯一性的载体,是个富对象,包含业务逻辑和唯一标识。值对象是属性的集合,没有唯一标识,只是数据的容器,没有业务逻辑。值对象是实体的一部分,为了简化设计,将部分相关属性抽离成值对象。如果值对象变动,原来的值对象可以直接丢弃。也可以理解为值对象是当时数据的快照,只是当时的状态。值对象过多会导致业务的缺失,影响查询性能。具体哪些属性可以作为值对象存在要具体问题具体分析。

    作者回复: 理解很透彻。

    2019-10-21
    2
  • 密码123456
    实体和值对象,就是把业务拆分,拆分再拆分。直到能够通过“对象”表达某一时刻的业务。实体就是业务中,不可再分割的对象。值对象是对实体的补充。举例:比如网购。商品最重要。商品就是实体,商品的状态比如下单,物流中。只是商品的状态,没那么重要的就是值对象。看到后面才发现,值对象和实体的定义是那么的难!

    作者回复: 抓住几个关键点就不那么难了。比如:实体可修改,值对象不可修改,只可以整体替换。实体是实实在在的业务对象,值对象只是对对象的描述。值对象依附以实体,实体没了值对象也就没了。

    2019-10-22
    1
  • 心浮天空
    值对象对实体而言的作用是什么?值对象的缺失是否会破坏实体的完整性?
    实体对象一般会对应着单独的功能对其信息维护, 而值对象没有单独的维护功能, 其生命周期与实体的生命周期一致?

    作者回复: 值对象是依附于实体的,是实体属性的一部分。它是实体的若干个属性的集合,为了概念完整性因此将具有一定业务含义的多个属性,组成一个属性集。
    实体的业务功能非常丰富,是业务对象的基本单元,值对象生命周期依赖于实体的,实体没有了,值对象也就没有了。

    2019-10-21
    1
  • 给心来块冰块
    实体对领域信息的具体化,值对象只是对实体的补充,而且这种补充具有整体的的意义

    作者回复: 是的。

    2019-12-11
  • 刘哲
    老师,其实我的想法里面,还是不建议将值对象的聚合做成一个序列化的数据放到同一张表里面,因为业务是会变更的,一期一些数据不需要修改,你作为json放在了数据库一列中,二期业务,这些数据可能就变成了可修改的,这样的业务场景很常见,所以我的建议是,只要是值对象的集合,就单独创建实体

    作者回复: 要根据自己的业务具体场景具体分析。值对象还是有它的价值所在的。

    2019-12-11
  • Alvin
    用项目结构来通俗的讲,实体就是我们平时项目中entity包中的类,与数据库表直接映射,值对象文章开头处一直误以为是view层的VO对象,后面才了解它其实就是实体中的属性对象。不知我这么粗浅的领悟对不对

    作者回复: 没错,理解正确。
    但是实体在不同的层有不同的形态,如PO,DO,DTO等。实体不一定与数据库表一一对应。

    2019-12-10
  • Kennedy
    老师,划分子域的依据是限界上下文,确定限界上下文的方式是根据业务语言的适用范围。我这个理解是否正确?如果一个业务语言属于子域,又属于该子域的子子域,那如何划分微服务呢?

    作者回复: 如果领域非常大的话,子域划分还需要一定的经验。当子域划分到适合进行事件风暴时,你就可以根据领域模型的语义来划分限界上下文了,限界上下文也是一种特殊的子域。限界上下文边界基本上就是微服务的边界了。

    2019-12-04
  • 冷たい風
    有点疑惑:将地址的属性值嵌入人员实体数据库表中,只创建人员数据库表?
    有如下二种方式:
    方式一:地址的每个属性平铺开,在人员数据表中分别创建对应的属性字段;
    方式二:人员数据表只新增一个字段,保存地址所有属性的json数据;
    这里指的是以上哪种方式呢,没说清楚呢

    作者回复: 两种方式都是一个人员表。第一种是地址铺开放,第二种是打包放。

    2019-12-03
    1
  • 江厚宏
    对于DDD,采用如MongoDB等非关系型数据库,是否能有效降低工程的开发成本呢?

    作者回复: 没尝试过MongoDB哈,应该还是要分场景吧。

    2019-12-02
  • Geek_aa8017
    老师你好,地址管理被设计成实体,订单中的地址被设计成值对象,如果地址管理的地址属性变了,怎么同步到订单管理的地址值对象呢?

    作者回复: 你需要有对应的功能,对订单管理的收货地址做整体替换。

    2019-11-20
  • Todd BD
    关于用用户的Address举例值对象我不是很明白, 因为值对象是不可变的,但是事实上用户也需要修改Address, 这个不变性如何理解? 是说从对象的角度, 只能以Address为粒度进行修改吗?

    作者回复: 值对象的不可变是指的整体不可变,也就是说不能改值对象里的某一个属性,它要被整体对待。地址在订单里是可以修改的,但是它只能整体替换。

    2019-11-16
  • Todd BD
    “实体以 DO(领域对象)的形式存在,每个实体对象都有唯一的 ID”
    想请教一下, 这个ID是指Entity的Identifier吗? 还是数据库中的主键ID?
    举个例子, 支付用的Payment Entity, 有业务上的Identifier, 就是Payment Number, 类似 XX-YY-ABC000001, 而Payment在数据库中对应的表中有id这个主键, 所以在Payment的这个DO中, 我用数据库的id来充当引用你那段话中的ID是否可以, 还是说需要使用Payment Number?
    再比如我要对Entity定义equals方法, 我是比较数据库主键, 还是比较这个Payment Number?

    作者回复: 实体有不同的形态,有数据库对象PO形态,有DO领域实体对象的形态,这个ID是你领域实体对象的ID。但是DO的这个ID可能会对应到数据库对象PO的ID。DO的这个ID在你定义实体的属性时候就确定了。
    你比较的时候应该是比较的DO的ID,但是这个DO的ID可能是在PO转换成DO的时候,来源于PO的ID。

    2019-11-16
  • 大鹏
    老师您好,有一点不是很理解,为什么DDD中唯一标识采用值对象方式,和传统的Long类型ID有什么优势,意义在哪,我理解当唯一标识未来需要扩展可以不改变对象索引,但唯一标识通常其实也不会改变哦,望解惑

    作者回复: 其实你把单一值对象理解成一个属性也没关系。一般很多人都认为值对象是属性的集合。

    2019-11-14
  • 等待......
    老师,请问下实体与领域服务边界是啥

    作者回复: 实体只管自己的业务行为实现,也就是方法。领域服务可以管一到多个实体的业务逻辑,面向应用服务。

    2019-11-13
  • 💢 星星💢
    这篇文章,刷新了我的眼界,一直都在传统行业工作,而且都是基于数据库出发做的设计,然后在设计实体,脑袋里根本也没有啥值对象,实体的概念,做开发时,基本上都是一个实体对应一张表,老师说的值对象可以嵌入到实体中,其实在设计中并没有这样多想。有了这些概念,然后跟着老师的课程学习,希望以后自己的知识更加体系化。下面是我对思考题的一些不成熟的见解。
    思考题:实体是业务组成的最小元素,并且也是表示业务形态的唯一标识,实体包含于值对象,值对象是对实体的补充,让实体更加充血丰富,通过值对象和实体的关系,建立的领域模型,可以使得架构面对将来复杂的业务更加灵活多变,我觉得在数据库设计中会有冗余字段信息,一些冗余信息的聚合也可以对应领域的值对象上。

    作者回复: 是的。

    2019-11-12
  • huaweichen
    学了这一课以后,简单的理解就是:
    在代码里面,人员和地址是两个类,
    数据库里面,人员和地址是一个表。

    但是请问老师,现在很多地方都会用到ORM,比如Doctrine。如果代码和数据不能很好的map

    作者回复: 要做DO和PO转换。

    2019-11-11
    1
收起评论
55
返回
顶部