您的当前位置:首页 > 热点 > 识别实体与值对象的特征 正文
时间:2026-11-15 来源:网络整理 编辑:热点
google霸屏优化【tg:seogoogle987】
甄别实体与值对象非常重要,正确与否会直接影响聚合的设计。
聚合是边界
在DDD中,聚合是实体与值对象的边界。一个聚合对外代表了一个完整的领域概念,遵循面向对象设计的基本原则,聚合内部往往由多个细小的高内聚领域概念组成。聚合内部的领域模型形成了一棵树,树的根必须是实体,可以称之为是聚合根(Aggregate Root),当然,也可以称之为根实体(Root Entity识别),它是聚合的唯一入口或出口。例如订单聚合定义了Order根实体,它就是订单聚合的唯一代言人。
在一个限界上下文的所有领域模型(实体和值对象)中,按照关系的强弱与概念的完整性,将其划分为多个聚合,就好像草原部落由一个个蒙古包构成了松散的聚居社群一般。
考虑到值对象与实体的差异,倘若需要管理它们的生命周期,则值对象不可能脱离聚合的边界单独存在。这就意味着,当我们要识别领域实体模型的聚合时,实体与值对象之间的强弱关系并不会影响到对聚合边界的界定。只要实体与值对象之间存在关系,无论关系强弱,该值对象都必须与存在关系的实体放在同一个聚合。如果一个值对象与多个实体之间存在关系,要么说明多个实体都属于一个聚合;要么意味着该值对象需要复制为多份,放到不同的聚合中,如下图所示:
如此一来,对于聚合边界的识别,就变成了对实体关系强弱的判断。只要我们正确地甄与值别了实体与值对象,在识别聚合时,就可以不再考虑值对象,如此就能降低识别的难度。
上下文的影响
虽然我们知道实体与值对象之间的本质差异在于是否具备唯一的身份标识(identity),然而许多时候,这一差异仍然显得似是而非。更何况,实体与值对象的定义并非绝对,在不同的上下文,同一个领域概念也可能定义为不同的设计类型。例如下图所示的钞票一枚:
在购买上下文,买卖双方只关对象注钞票的面值与货币类型,只要值相等,即可认为是同一个对象,因而需定义为值对象;在印钞上下文,每张钞票都具有一个唯一的标识,即使同为100元的人民币,只要ID不同,也会认为是不同的对象,故而定义为实体。因此,要正确地甄别实体与值对象,需要结合具体的上下文。
识别的特征
即便如此,仍然缺乏相对客观的判断标准。为此,我总结了如下几个特征。
相等性
甄别实体与值对象,可以首先的特从相等性进行判断。只要一个领域模型对象的属性值相等,就认为是同一个对象,应优先考虑建模为值对象;否则,需要为领域模型对象定义唯一标识,并建模为实体。
注意:在进行相等性判断时,不能将作为唯一标识的ID视为领域模型的属性。
例如地址领域概念,只要其属性值国家、省份、城市、街道与邮政编码相等,就可以认为是同一个地址,应将Address类定义为值对象。对于大家耳熟能详的订单领识别域概念,显然需要为其分配一个唯一的订单编号,因为理论上可能存在除订单编号外其他属性都相同的两个不同订单,应将Order定义为实体。
然而,在对相等性进行判断时,可能出现ID与属性存在一种隐含的对应关系。例如,出版行业中作为正规出版物的图书,具有唯一的ISBN号,它相当于是图书领域概念的ID,所以Book应定义为实体。可在对Book相等性进行判断时,也可以不通过IS实体BN进行相等性判断,基本上,只要书名、作者(译者)、出版社、价格、出版日期、版次、页数、字数等属性值相同,也可以认为是同一本书,那是否意味着可以将Book定义为值对象呢?
显然,在进行相等性判断时,考虑的属性越多,就会出现多个组合的属性形成一种“隐藏”的唯一标识特征,有一些体现业务规则的ID,自身就是根据属性值来定义的。例如,航班的唯一标识就可以根据承运公司二字码、航班与值号、起降机场三字码与执飞日期来决定。通过唯一标识固然可以决定是否同一个航班,根据映射的多个属性值,也可以判断相等性。这会让人在甄别实体与值对象时,显得摇摆不定。例如,腾讯会议的会议号是Meeting的身份标识,在比较会议的相等性时,倘若我们考虑了除会议号之外的其他属性,如会议名称、会议类型、开始时间、结束时间、创建人、创建时间等属性,不一样可以确定会议的相等性吗?
因对象此,除了判断相等性,还需考虑不变性。
不变性
Eric Evans建议将值对象定义为不变的类,实则是因为根据值判等的值对象就应该具有不变性。仍以购买上下文的钞票为例,50元+50元=100元,这100元与原来的50元是另一张不同的钞票:
反之,一个对象除了ID,其余属性值都可以修改,不需要创建一个新的对象,就可以认为该领域对象是可变的,应考虑定义为实体。如前所述的Mee的特ting对象,只要meetingId值不变,如会议名称、会议类型、开始时间、结束时间这样的属性值即使发生了天翻地覆的变化,我们也认为它是同一个会议。显然,应将Meeting定义为实体。
再考虑一个典型的订单聚合:
为什么我们要将订单聚合中的OrderItem定义为实体?如果不考虑ID属性,只要orderId、product与quantity值相同,完全可以认为是同一识别个订单项。然则,订单项的quantity值是可以更改的,更改了数量的订单项也不会认为是不同的订单项。订单项的可变性决定了它应该定义为实体。
为何要将OrderItem的Product属性定义为值对象呢?要知道,该Product类型还定义了productId属性,既然具有身份标识,不应该定义为实体吗?因为在订单上下文中,商品的productId来自于商品上下文的实体商品ID,在订单聚合中,可以将productId视为Product类的属性值。只要productId、name和price值相同,就可以认为是同一个商品,且它们的值是不变的。这正是将Product定义为值对象的原因所在。
独立性
即使考虑了相等性和不变性,仍有一种例外情形,那就是考虑独立性特征。值对象作为实体的属性必定附属于实体,不能单独存在;如果一个领域对象既满足了与值相等性,又满足了不变性,可定义为值对象;可是,如果它单独存在,且需要管理其生命周期,就需要将这样的类“升级”为实体。
考虑考勤上下文的假期领域概念。由于中国农历假期的缘故,每年都需要配置新的假期。假期概念对应的Holiday类定义为:
显然,该类的所有属性值相等,即可认为是同一个假期,一旦修改了假期的值,也可以认为是不同的假期,即Holiday类同时满足相等性和不对象变性,应定义为值对象。可是,在考勤上下文的领域模型中,Holiday类是完全独立的,不依附于其他任何实体,而它也需要管理生命周期。这时,就应遵循独立性特征,将其“升级”为实体。
优先级
以上三个特征并无重要性排列,需综合考虑。如果仍然无法判断,就遵循优先级原则:优先将领域概念建模为值对象。
标签: 小米汽车 李女士 定金返还 格式条款2026-10-02
3D视觉CV界的终极体现形式,计算机如何「看」这个三维世界2026-06-16
标签: 中国移动 2026年一季度报告 财报 通信运营商2026-08-25
字节跳动推出全新3D 生成模型 Seed3D2.0,技术跃升至 SOTA 水平2026-07-21
OpenAI再放大招!全新图像模型即将登场,复杂图表生成能力或迎质变2026-08-05
标签: Apple Pay 飞度 小米YU7 死了么2026-08-05
MIT给激光雕刻机安上AI,自动辨别材料确定雕刻力度,准确率达98%2026-07-28
京东科技京东云事业群副总裁金旸:每一家成长中的企业都将经历数字化转型的历程2026-09-02
mc子龙是什么梗2026-09-06
麻省理工科技评论携金隅智造工场“寻找聪明公司”智能制造专场路演圆满收官2026-09-07
亚马逊和两位女员工和解:解雇仗义执言者遭舆论炮轰2026-09-12
标签: 特斯拉 Model S X Optimus2026-08-22
苹果藏大招?传用自研芯片做云,要给亚马逊们“降降价”?2026-06-22
标签: 擎天租 SHAREBOT 正大机器人 美格智能2026-06-20
标签: 云知声2026-09-26
标签: 巨人网络 超自然行动组 史玉柱 刘伟2026-05-20
谷歌Gemini 3.0 Pro内测流出:编程能力大跃进,下周即将上线2026-08-01
字节跳动AI助手Cici在海外多国应用榜登顶:与国内豆包采用双品牌策略2026-07-16
贝索斯谈亚马逊竞争:成为最好的企业之一是不够的2026-08-22