首页 > 其他分享 >DDD你真的理解清楚了吗?怎么准确理解“值对象”

DDD你真的理解清楚了吗?怎么准确理解“值对象”

时间:2024-12-26 22:41:02浏览次数:6  
标签:对象 用户 订单 理解 真实世界 设计 上下文 准确 DDD

这些年,随着软件业的不断发展,软件系统开始变得越来越复杂而难于维护。这时,越来越多的开发团队开始选择实践DDD领域驱动设计。领域驱动设计是一种非常优秀的软件设计思想,它可以非常好地帮助我们梳理复杂业务,解决大规模业务系统的设计开发与更新维护。但是,领域驱动的学习成本却非常高,使得很多同学难于准确地理解DDD,更难于真正落地实际项目的设计编码。为此,我通过这一系列知识分享,让大家真正准确地理解DDD中这些晦涩的概念,特别是让大家理解最终是怎么落地到软件项目的设计开发中的。

今天,我们首先探讨的是在DDD中,让大家最头疼、最晦涩的概念——什么是“值对象”?要理解“值对象”的设计思想,首先我们先来梳理一下领域驱动的核心思想。领域驱动认为,软件的本质就是对真实世界的模拟,软件中所有业务逻辑正确与否,唯一的判定标准就是,是否与真实世界保持一致。如果一致,设计就是OK的,否则用户就会提BUG,或者变更需求。只要理解了这个本质,软件设计就简单了:我们首先理解真实世界的业务,然后将我们对业务的理解形成软件设计。

然而,这里有一个问题,那就是软件是怎么与真实世界对应的呢?这种对应体现在以下三个方面:

1)真实世界有什么事物,软件世界就有什么对象;

2)真实世界中这些事物有什么行为,软件世界这些对象就有什么方法;

3)真实世界中这些事物间有什么关系,软件世界中这些对象就有什么关联。

因此,我们在软件设计时,首先以业务场景为单位,一个一个地分析每个业务场景都有哪些领域对象,以及它们相互之间的行为与关系,形成领域模型。然后再以领域模型为核心,完成软件的设计与开发。

譬如说,我们要设计一套电子商务系统,按照业务需求会划分为很多功能,那么每个功能就是一个业务场景。譬如在“下单”这个业务场景中,在真实世界中都有哪些事物呢?首先有“订单”,可以形成订单对象;每个订单对应一个用户,但一个用户可以有多个订单,所以从订单到用户是一个“多对一”关系;一个用户有多个地址,然而一个订单只能对应一个地址……如下图,我们按照这样的步骤逐一分析领域对象和它们之间的关系。最后,我们对订单有什么操作呢?有“下单”、“支付”、“查看订单”……

这就是领域模型,订单、用户、地址、订单明细等类,都是领域对象。然而,在DDD中还要把领域对象严格区分为“实体”与“值对象”。这时,很多同学就比较晕,什么是实体?什么是值对象?为了准确理解这个地方,我们先看看《领域驱动设计》原著是怎么说的。

实体(Entity):又称为Reference Object,它具备生命周期,并且在生命周期的过程中,其形式和内容都有可能发生变化,但它的标识永远不变。也就是说,每个实体都有一个唯一的标识,用于区分真实世界中的“他”与其他人,比如用户ID。实体是有生命周期的,比如用户的注册与注销;实体中的一切都可能会变,比如小张将自己的账户转让给了李四,但账户ID是不会变的。这个唯一的标识就是主键,以这种形式的设计,用户有用户ID、账户有账户ID、订单有订单ID,就是实体的设计。很显然,这样的设计大家都能够理解,关键是“值对象”。

值对象(Value Object):在《领域驱动设计》这本书中对值对象的描述比较隐晦,但我们大致可以归纳为以下几个特征:对象声明与对象中的属性都是不变的,可以为多个对象所引用与共享(而不是复制),这就是“值对象”。该怎样来理解这几个特征呢?

譬如,在真实世界中,一个用户可以有多个订单,那么在订单查询时,每个订单就是一个订单对象,每个订单对象都有各自不同的订单ID。因此,订单的设计是实体。然而,每个订单都要引用一个用户,也就是指向一个用户对象。那么,同一个用户的多个订单指向的是谁呢?显然,不能将这个用户复制成多个对象,而是所有这几个订单都引用的是这一个对象。也就是说,这里的“用户”对象是值对象。

然而,值对象又必须是不变的,这就是说,如果“用户”是值对象,那么用户及其相关的属性都必须是不变的。但现实情况是,用户及其用户信息都是可变的,我们会对用户信息进行增删改操作。是的,在真实世界中,一切都是在变化,没有什么是不变的。那么,怎么来理解值对象的不变性呢?

在DDD的领域建模中,除了有领域模型以外,还有一个非常重要的设计叫“限界上下文”。领域模型是描述的真实世界,但真实世界又是无限大的,那么领域模型该如何描述真实世界呢?DDD将一个复杂系统的业务划分成很多个限界上下文,然后对每个限界上下文中进行领域建模。这样,每个领域模型都有各自的边界,我只是在这个边界中描述我的业务。这样的设计,就将纷繁复杂的世界“分而治之”,对每个领域模型的分析就变得简单了。

譬如在以上案例中,可以首先将对用户及其用户档案的管理划分成一个上下文,叫“用户上下文”。在这个上下文中,用户及其属性是可变的,要进行增删改的操作,因此“用户”对象的设计是实体。然而,在另一个“订单上下文”中,订单是实体,要对其进行增删改,但订单引用的“用户”以及“地址”就是值对象。也就是说,在订单上下文中,“用户”以及“地址”是只读的,仅仅用于订单对象的引用,而不会对其进行增删改操作。这样,“用户”以及“地址”作为值对象,就体现了它的只读与不变性。

此外,站在开发的角度来说,领域模型最终要落实到软件开发。如果采用微服务的设计,就会将“用户上下文”与“订单上下文”划分为用户微服务与订单微服务。在划分微服务的同时,也会划分数据库,用户微服务有用户数据库,订单微服务有订单数据库。有了这样的设计,用户表必然是设计在用户数据库中,而不是在订单数据库中。当订单微服务要查询订单时,通过调用用户微服务的接口获得订单相关的用户对象。然而,这些用户对象只存在于订单微服务的内存中,是只读的,而不会存储在订单数据库中去增删改。这就是“值对象”的概念及其设计实现。

总而言之,DDD的实体在本上下文中是可读可写的,而值对象是只读的。在一个上下文中的核心业务是对实体的增删改,而值对象是与实体相关联的,仅仅用于实体的引用与查询的对象。值对象的特性是只读,但在实际项目中的表现有2种形式:

1)  对其它微服务中对象的引用,需要调用其它微服务的接口获得,数据不在我本地的数据库中,仅仅存在于内存中,并且不能修改,只能查询;

2)  一些类似类型、种类、类别的字典数据,虽然数据存储在本地数据库中,但没有增删改的功能,只有查询与引用。例如会员等级、积分规则、支付方式,等等。

(待续)

标签:对象,用户,订单,理解,真实世界,设计,上下文,准确,DDD
From: https://www.cnblogs.com/mooodo/p/18634338

相关文章

  • 深入理解c++中的using
    大家好!我是兔飞飞女士!前两天太忙了,凌晨五点多起来当志愿者。现在终于有点时间了。今天学习using!using是C++中的一个关键字,通常有两种常见的用途:引入命名空间:你可以使用using来避免每次都写命名空间的前缀。例如,C++中标准库的很多功能都在std命名空间下,所以通常......
  • 对于资源管理的一些理解
    项目资源管理是项目管理中的一个关键领域,旨在确保项目所需的所有资源(人力、物力、设备、资金等)能够被合理规划、获取、开发、管理和控制,以确保项目的成功。凡战之道,未战养其财,将战养其力,即战养其气,既胜养其心-- 苏洵《心术》1.规划资源管理(PlanResourceManagement)(未战......
  • 中考阅读理解深入逻辑分析-006 A Stream's Journey to the Sea 一条小溪通往大海的旅
    文章正文Alittlestreamrandownfromahighmountainfar,farawaythroughmanyvillagesandforests,untilitreachedadesert.Thestreamthenthought,“I’vebeenthroughcountlessdifficulties.Ishouldhavenoproblemcrossingthedesert!”Butasshes......
  • 用小学生都能理解的方式介绍 TF-IDF 算法
    用小学生都能理解的方式介绍TF-IDF算法什么是TF-IDF?举个例子:小猫和小狗的故事1.计算TF(词频)2.计算IDF(逆文档频率)3.计算TF-IDFTF-IDF的特点另一个例子:更直观的理解总结在信息检索和文本挖掘中,TF-IDF是一个非常重要的算法。它可以帮助我们找到文档中最重要......
  • 算法网关视频分析网关:视频分析技术的准确性和实时性是如何确保的?
    在当今数字化时代,视频分析技术已成为安全监控、交通管理等多个领域不可或缺的工具。然而,确保视频分析技术的准确性和实时性,尤其是在多变的环境条件下,是一个复杂而重要的挑战。以下是一些关键技术和策略,它们共同确保了视频分析技术在各种条件下都能提供高效、准确的结果。1、图像......
  • 【 深入理解SringBoot@PathVariable】
    深入理解@PathVariable@PathVariable是Spring框架中的一个注解,主要用于将URL中的模板变量映射到处理器方法的参数上。这个注解允许开发者从请求的URL中提取出特定部分的数据,并直接作为方法参数传递给控制器(Controller)的方法。它在构建RESTful风格的Web服务时特......
  • 【深入理解@Profile】
    深入理解@Profile@Profile是Spring框架中的一个注解,它允许开发者根据当前的环境(如开发、测试或生产环境)来注册不同的bean到Spring应用上下文中。这对于多环境配置非常有用,因为不同的环境可能需要不同的数据源、配置或其他资源。以下是对@Profile注解的详细解释:一、@Profil......
  • SQL大宝剑-已燃尽所有SQL的理解
    作者:京东物流向往一、背景从事数据开发将近四年,过程中有大量任务交接或阅读同事代码的场景。在这些场景中发现有些SQL读起来赏心悦目,可以一目了然地了解业务逻辑,一些复杂的业务需求实现方法也可以做到简洁优雅,同时在性能上也有良好表现。而有些SQL读起来非常艰难,时常要跨越几百......
  • 【通俗理解】Hopfield网络可以被视为一个智能的“记忆盒子”,它能够记住一系列模式,并在
    【通俗理解】Hopfield网络——智能记忆与联想的神经网络关键词提炼#Hopfield网络#递归神经网络#联想记忆#能量函数#吸引子#图像恢复#优化问题第一节:Hopfield网络的类比与核心概念【尽可能通俗】Hopfield网络可以被视为一个智能的“记忆盒子”,它能够记住一系列模式......
  • Python中一切皆为对象,这样理解!
    """在python中一切皆为对象,变量是对象,函数是对象,类也是对象。对象(object)是指在内存中具有唯一标识符(id)、类型(type)和值(value)的实例。换句话说,对象是一个具有属性和方法的实体,这些属性和方法可以被访问和操作。(1)唯一标识符:其实就是对象在计算机内存中的地址。可使用内置......