作者:知一雫話

领域基本概念字典

资料来源: https://noo gel.XYZ/2021/01/15/1.html

域驱动设计定义了非常多的概念。 如果不找很多资料综合看,就很难正确理解。 以下是对大多数域驱动概念的集合组织、理解和阐述。

战略设计和战术设计战略设计主要从业务角度出发,构建业务领域模型,划分领域边界,建立通用语言边界上下文,边界上下文可以作为微服务设计的参考边界。

那是我们从高层事业来绅士的软件系统。

从战略设计的角度看,一系列基础性电子商务业务应包括支付域、交易域、商品域、库存域、履约域。

不同区域之间根据边界的上下文划分边界。

战术设计从技术角度出发,侧重于领域模型的技术实现,完成软件开发和落地。 它包括聚合根、实体、值对象、域服务、应用服务和存储库等代码逻辑的设计与实现。

主要关注技术实现,是程序员最现实的地方。

战术设计的具体落地例子将在后面的内容中说明。

域子域DDD的域是要在此边界内解决的业务问题域。

领域既然用于限定业务的边界和范围,那么大小就有区别,领域越大,业务范围就越大,反之亦然。

区域可以进一步分成子区域。

多个划分的子域称为子域,每个子域对应一个更小的问题域或更小的业务范围。

在划分域的过程中,核心域公共域支持域将细分为不同的子域。 根据自身重要性和功能属性,子域可以分为三个子域:核心域、公共域和支持域。

决定产品和公司核心竞争力的子域是核心域它是业务成功的主要因素和公司的核心竞争力。

鲜有个性诉求,在多个子域中同时使用的公共功能子域是公共域。

另一个功能子域是必需的,但支持域既没有决定产品和公司核心竞争力的功能,也没有通用功能。

根据上述概念的定义,将订单域划分为: 其中,交易子域和评价子域是最重要的核心子域,子域的限购、交付、报表子域、会员注册子域是支持子域,消息子域连接各子域

请注意,此处的曲线用于区分不同的子域类型,而不是边界上下文。

事件风暴是一种团队活动,域专家和项目团队以头脑风暴的形式,将域中所有的域事件进行罗列和合并,形成最终的域事件集合,针对每个事件,归并触发该事件的指令

标记每个事件的命令启动器角色。

命令由用户发起,或者在第三方系统调用或计时器触发器等最后对事件进行分类,以组织实体、聚合、聚合根和边界上下文。

事件风暴是DDD战略设计中常用的方法之一,可以快速分析和分解复杂的业务领域,完成领域建模。

公共语言边界上下文在DDD领域的建模和系统构建过程中,有很多参与者,包括领域专家、产品经理、项目经理、架构师、开发经理和测试经理。

对于同一领域的知识,根据参加的角色不同可能会有不同的理解,但会妨碍大家交流。 我该怎么办? 因此,DDD中出现了“公共语言”和“边界上下文”这两个重要概念。

这两者是互补的,公共语言定义上下文的含义,边界上下文定义域边界,使得每个上下文的含义在其特定边界内具有唯一性,域模型存在于边界内。

通用语言团队沟通中达成共识的、能够明确、明确地记述业务规则和业务含义的语言为通用语言。

解决各岗位沟通障碍问题,促进不同岗位合作,确保业务需求的准确表达。

通用语言贯穿于整个设计过程,能够基于通用语言开发可读性更高的代码,能够将业务需求正确地转换为代码。

边界上下文用于封装公共语言和域对象,提供上下文环境,确保域中的某些术语、业务相关对象等具有确切含义,不是二义的。

此边界定义了模型的应用范围,使团队的所有成员都清楚地知道哪些应该在模型中实现,哪些不应该在模型中实现。

栗表示是商品领域,商品实体对应SKU商品,包括标题和金额,如现在的课程、会员服务。

订单域的商品实体与域的商品域的实体不同。 例如可以做成可以销售优惠券的商品。 coupon_no是产品_ key。

具有非可合并属性; 或者打包付费咨询的用户服务并将其作为商品销售,member_id将映射到producer_key,感觉具有consumable属性。

边界上下文是指区分不同区域下的区域对象,划定区域对象语义的边界。

在订单域中,商品实体默认可以是商品系统SKU,也可以是优惠券或用户服务等。

上下文映射图上下文映射图用图表示n个上下文之间的映射关系。

ACL表示防腐层,OHS表示开放主机服务,PL表示发布语言,u表示上游,d表示下游。

您是否遇到过这样的问题:域服务希望对域概念进行建模,但不适合将其放在实体中,也不适合放在值对象中? 而且,我在烦恼自己的模型化方法是否有问题。

恭喜你。 恭喜你。 你的建模方法完全没有问题。 只是,我还没有接触到域服务这个概念。 因为域服务本来就是为了应对这种场面而来的。

例如,要确定客户端类型和版本是否支持功能,可以创建ClientVersionService来负责。

有趣的是,域服务与上述APP应用服务不同,域服务是域模型的一部分,而APP应用服务则不是。

APP应用服务是域服务的客户,它将域模型转变为外部可用的软件系统。

域事件DDD允许域事件用于解决上述问题。 在这种情况下,将使用最终一致性而不是事务一致性,并且域事件将实现组件之间的数据一致性。

领域事件的命名遵循英语“名词动词过去分词”的格式。 也就是说,表示以前发生过的事情。

例如,假设购买者提交了商品订单,然后发出OrderCreated事件,用户支付TradePaid事件。

需要注意的是,既然是领域事件,他们便应该从领域模型中发布。

领域事件的最终接收者可以是本限界上下文中的组件,也可以是另一个限界上下文。

领域事件的额外好处在于它可以记录发生在软件系统中所有的重要修改,这样可以很好地支持程序调试和商业智能化。

另外,在CQRS架构的软件系统中,领域事件还用于写模型和读模型之间的数据同步。

再进一步发展,事件驱动架构可以演变成事件源,即对聚合的获取并不是通过加载数据库中的瞬时状态,而是通过重放发生在聚合生命周期中的所有领域事件完成。

实体 值对象 聚合 聚合根实体 值对象实体和值对象是组成领域模型的基础单元。

在DDD 中有这样一类对象,它们拥有唯一标识符,且标识符在历经各种状态变更后仍能保持一致。

对这些对象而言,重要的不是其属性,而是其延续性和标识,对象的延续性和标识会跨越甚至超出软件的生命周期。

我们把这样的对象称为实体。

通过对象属性值来识别的对象,它将多个相关属性组合为一个概念整体。

在DDD 中用来描述领域的特定方面,并且是一个没有标识符的对象,叫作值对象。

值对象本质就是一个集合,可以保证属性归类的清晰和概念的完整性。

举例说明

消费者实体原本包括:ID、昵称、注册手机号、姓名以及人员所在的省、市、县和街道等属性。

这样显示地址相关的属性就很零碎了对不对?现在,我们可以将“省、市、县和街道等属性”拿出来构成一个“地址属性集合”,这个集合就是值对象了。

聚合 聚合根聚合是业务和逻辑紧密关联的实体和值对象组合而成,聚合是数据修改和持久化的基本单元,一个聚合对应一个数据的持久化。

聚合在DDD分层架构中属于领域层,领域层包含了多个聚合,共同实现核心业务逻辑,聚合内的实体以充血模型实现个体业务能力,以及业务逻辑的高内聚。

跨多个实体的业务逻辑通过领域服务来实现,跨多个聚合的业务逻辑通过应用服务来实现。

如果把聚合比作组织,聚合根则是组织的负责人,聚合根也叫做根实体,它不仅仅是实体,还是实体的管理者。

聚合之间通过聚合根关联引用,如果需要访问其他聚合的实体,先访问聚合根,再导航到聚合内部的实体。

即外部对象不能直接访问聚合内的实体。

举例说明

上图说明聚合与聚合根的关系,交易聚合有一个唯一的聚合根交易单,交易单组织了消费者实体、商品实体、商铺实体、优惠券实体同时消费金额之对象。

下面具体对比说明下:

聚合的特点:高内聚、低耦合,它是领域模型中最底层的边界,可以作为拆分微服务的最小单位,但我不建议你对微服务过度拆分。

但在对性能有极致要求的场景中,聚合可以独立作为一个微服务,以满足版本的高频发布和极致的弹性伸缩能力。

一个微服务可以包含多个聚合,聚合之间的边界是微服务内天然的逻辑边界。

有了这个逻辑边界,在微服务架构演进时就可以以聚合为单位进行拆分和组合了,微服务的架构演进也就不再是一件难事了。

聚合根的特点:聚合根是实体,有实体的特点,具有全局唯一标识,有独立的生命周期。

一个聚合只有一个聚合根,聚合根在聚合内对实体和值对象采用直接对象引用的方式进行组织和协调,聚合根与聚合根之间通过ID 关联的方式实现聚合之间的协同。

实体的特点:有ID 标识,通过ID 判断相等性,ID 在聚合内唯一即可。

状态可变,它依附于聚合根,其生命周期由聚合根管理。

实体一般会持久化,但与数据库持久化对象不一定是一对一的关系。

实体可以引用聚合内的聚合根、实体和值对象。

值对象的特点:无ID,不可变,无生命周期,用完即扔。

值对象之间通过属性值判断相等性。

它的核心本质是值,是一组概念完整的属性组成的集合,用于描述实体的状态和特征。

值对象尽量只引用值对象。

防腐层通过在遗留系统和现代系统之间使用防腐层来隔离它们。

该层转换两个系统之间的通信,允许遗留系统保持不变,同时可以避免损害现代应用程序的设计和技术方法。

现代应用与防腐层之间的通信始终使用应用程序的数据模型和架构。

从防腐层到遗留系统的调用都符合该系统的数据模型或方法。

防腐层包含两个系统之间转换所需的所有逻辑。

该层可以作为应用程序中的组件或作为独立服务来实现。

贫血模型贫血模型就是模型对象之间存在完整的关联(可能存在多余的关联),但是对象除了get和set方外外几乎就没有其它的方法,整个对象充当的就是一个数据容器,用C语言的话来说就是一个结构体,

所有的业务方法都在一个无状态的Service类中实现,Service类仅仅包含一些行为。

贫血模型的优点是很明显的:

被许多程序员所掌握,许多教材采用的是这种模型,对于初学者,这种模型很自然,甚至被很多人认为是java中最正统的模型。

它非常简单,对于并不复杂的业务(转帐业务),它工作得很好,开发起来非常迅速。

它似乎也不需要对领域的充分了解,只要给出要实现功能的每一个步骤,就能实现它。

事务边界相当清楚,一般来说service的每个方法都可以看成一个事务,因为通常Service的每个方法对应着一个用例。

,如何保持业务逻辑一致是很大的挑战。

领域模型领域模型是对领域内的概念类或现实世界中对象的可视化表示。

又称概念模型、领域对象模型、分析对象模型。

它专注于分析问题领域本身,发掘重要的业务领域概念,并建立业务领域概念之间的关系。

领域驱动模型,与贫血模型相反,领域模型要承担关键业务逻辑,业务逻辑在多个领域对象之间分配,而Service只是完成一些不适合放在模型中的业务逻辑,它是非常薄的一层,它指挥多个模型对象来完成业务功能。

其优点是:

领域模型采用OO设计,通过将职责分配到相应的模型对象或Service,可以很好的组织业务逻辑,当业务变得复杂时,领域模型显出巨大的优势。

当需要多个UI接口时,领域模型可以重用,并且业务逻辑只在领域层中出现,这使得很容易对多个UI接口保持业务逻辑的一致(从领域模型的分层图可以看得更清楚)。

其缺点是:对程序员的要求较高,初学者对这种将职责分配到多个协作对象中的方式感到极不适应。

领域驱动建模要求对领域模型完整而透彻的了解,只给出一个用例的实现步骤是无法得到领域模型的,这需要和领域专家的充分讨论。

错误的领域模型对项目的危害非常之大,而实现一个好的领域模型非常困难。

对于简单的软件,使用领域模型,显得有些杀鸡用牛刀了。

开放主机服务该模式可以通过REST实现。

通常来讲,我们可以将开放主机服务看作是远程过程调用的API。

同时,也可以通过消息机制实现。

参考https://www.cnblogs.com/snidget/p/12995676.htmlhttps://zhuanlan.zhihu.com/p/130945830https://blog.csdn.net/itfly8/article/details/109554847https://www.cnblogs.com/netfocus/archive/2011/10/10/2204949.htmlhttps://iambowen.gitbooks.io/cloud-design-pattern/content/patterns/anti-corruption-layer.html

作者:知一杂谈

出处:https://noogel.xyz/2021/01/15/1.html