领域驱动设计-聚合,一种极简的思惟模式
引言
做为IT技术产业飞速发展的产物,软件工程学已经成为当今时代很是重要的一个学科。做为一名资深的软件开发从业者,咱们须要学习的东西实际上已经远远超出了本来在大学教育阶段所接受的知识深度和广度,领域驱动设计更是如此。固然必须认可的是大学阶段开了不少扇窗,直到今天才深入体会那些平时看起来绝不起眼的学科(如图论、几率论、高等代数),实际上对软件领域的影响已经远远超出了咱们的想象,例如,若是想作AI,没有扎实的数学和图论基础,显然只能成为工具的使用者,而非技术专家。html
有许多读者提到,笔者的内容缺少实际例子,在具体阅读时,很难造成带入感。主要是由于领域驱动设计思想自己体系庞大,细节很是多,这须要在平常学习之余多加思考,细细的品味知识中的奥妙,笔者也是按照一样的思路来指导本身的学习过程的。坦率而言,要把这些概念的名词都记住,显然很容易,可是要理解这些名词的具体含义以及实际应用场景,却须要更多的思考,这也一样是软件工程博大精深的奥妙所在。数据库
领域生命周期的复杂性是如何影响设计的
咱们都清楚领域驱动设计,做为应对复杂情形下的软件工程思路,实际上受到了传统软件思惟的普遍影响,例如以前提到的实体和值对象、以及服务和包(模块)实际上在非领域驱动设计中一样广泛存在。可是聚合和聚合根的思想,应该属于领域驱动设计中独特的知识点,进一步增强这个知识点的认识,将有助于咱们更好的进行聚合设计,从而更好的设计一个符合实际应用场景的应用系统。 微信
在上一篇文章中,咱们了解到,领域驱动的五个基本部分(关联,实体,值对象,服务和模块),他们是构成软件体系的最基础元素。在一个简单的软件系统中,每每只需使用这些元素的简单组合便可完成单个模块功能的开发,并且显然速度很是迅速。可是咱们也将一样面对一些对象,他们具备更长的生命周期,也许有至关一部分时间,是经过复杂的数据持久化处理机制、甚至是跨数据源、跨服务来完成,这意味着不是单纯的依靠一块内存空间来度过的。它们与其余对象有着复杂的依赖关系,在它们漫长的生命周期中,会根据不一样场景的规则、经历许屡次状态的变化。对于这些对象的操做,稍不留心,就会致使代码间的耦合度急剧提高,甚至成为软件系统中最难以维护的代码块,这实际上偏离了模型驱动设计的理想轨道,成为经验设计史上的一大典型问题。并发
领域驱动设计认为,这种复杂过程的操做对模型驱动设计带来的影响主要包括如下两个方面: 工具
一、维护对象间,在整个生命周期中的完整性:对象依赖不一样的数据源或存储机制或内存单元时,完整性将难以保障。学习
二、陷入管理生命周期复杂性形成的困境中。同上,要维护这套具备复杂体系的模型结果,自己成为一个问题。ui
聚合,让设计简化
领域驱动设计思想针对这两种场景,设计了聚合(Aggregate)对象来解决这个问题,并使用工厂对象和仓储对象来对生命周期进行管理,因为时间和篇幅的关系,我这一篇先介绍聚合对象和聚合根,下一篇在介绍工厂对象和仓储对象。url
实际上咱们很容易就设计出一个具备复杂关系的对象,例如,Person对象,实际上可能关联了地址和工做等不一样的实体或者值对象,若是要对数据进行删除,可能倾向于直接删除Person对象,而保留其余对象;或者删除Person对象时,同时删除地址对象。可是这两种方式都并不是很是合理的策略,在于方式一,会在数据库中造成冗余数据,不利于后期数据的维护管理;然后者则可能致使依赖于地址的其余Person出现异常。spa
即便是再简单的场景,遇到并发访问时,也会存在问题。因为不一样的用户对系统中的数据的访问是随机分布的,意味着有可能会形成多个用户同时修改相互依赖的对象,进而形成系统可用性的急剧降低。.net
所以,在具备复杂关联的模型中,要想保证数据更改的一致性是很困难的。不只互不关联的对象须要遵照必定的规则,并且紧密关联的对象间操做一样也存在规则。常用的一种方式多是事务锁,可是设计谨慎的锁机制,当然能够解决这个问题,可是可能致使用户间的操做不可控,系统变得不可用。事实上数据库层面的行锁和表锁,也是为了解决这些问题提供的思路,可是这种方案实际上分散了人们对于模型的注意力,使得系统流程的设计过程自己就至关臃肿。这也是古老的系统用户体验不佳的一个主要缘由。
领域驱动设计认为,表面上看是对数据操做层面的技术问题,可是它的根源依然是因为模型的设计依然是基于实体关系模型的设计,而缺少明肯定义的边界。认为经过一个合理的模型的设计,能够是模型更加理解,而且使设计过程更易于沟通。当模型被修改时,它也将引导咱们对实现进行修改。
这种模式,就是聚合模式(Aggregate)。这种来源于制造业体系中的模型,简单但严格,可是能够提供新的思路。
领域驱动设计中,认为实现这个聚合模型,应当包含如下要素:
一、经过一个顶层抽象来封装模型中的引用。使用Aggregate对象,实现一组相关对象的集合,做为数据修改的单元。
二、每一个Aggreate对象具备一个根和边界。边界,用以定义Aggreate内部都有什么。而根是Aggregate对外暴露的特定实体。对Aggregate而言,外部对象只能够引用根,而边界内部的对象则能够相互引用。
三、除根以外的全部实体,在Aggregate内部都有惟一标识,但外部对象只能看到根实体而没法看到其余实体。
对Aggregate的操做,应该按照必定的规则,确保数据变化时,可以保持一致性。而任何跨越Aggregate的规则,则不要求每时每刻都保持最新状态,跨越经过事件处理、批处理或者其余更新机制,使依赖项在规定的时间内获得解决。可是在Aggregate内部,规则必须获得知足。
这意味着,对于这个Aggregate的操做,必须应用更加具体的规则,包括但不限定于如下内容。
1、聚合根Entity,具备全局标识,表明整个Aggregate对外提供服务,并最终负责检查规则。
2、边界内的对象具备本地标识,但仅限于Aggregate内部保持惟一性。
3、Aggregate外部的对象不能引用除根Entity以外的其余内部对象。根能够将内部对象的引用传递给外部对象,可是外部对象只能使用,而不能保持引用更不能操做。这也意味着,根能够将值对象的副本传递给外部对象,由于它只是一个属性值,而不是一个完整的生命周期对象。
4、只有Aggregate的对象才能经过数据库查询直接完成,而其余对象应该在建立后,经过根的对象遍历关联来发现。
5、Aggregate内部对象,能够引用外部的Aggregate根对象的引用(不能反过来)
6、删除操做,应该一次性删除Aggregate边界内的全部对象。
7、对Aggregate内部任何对象的操做,必须保证上述规则都获得知足。
总结
Aggregate对象其实是经过划分一个界限清晰的范围,确保在Aggregate对象的生命周期内,对范围内对象每一个阶段的操做都知足规定规则。
对Aggregate对象的定义和分析是一件很是细致的工做,咱们应该根据实际应用场景,将实体和值对象分别汇集到Aggregate中,定义好边界和根后,经过根Entity来控制对边界内部其余对象的访问。只容许外部对象引用根,并在一次操做中,临时引用内部成员。但不能经过根来修改内部对象,这种设计有利于Aggregate内部的对象知足规则,也能保证它自己可以做为一个总体知足规则。而对Aggregate对象上的操做,是经过下一篇提到的Factory和Repository来实现的,它们分别在不一样的阶段,实现了对象转化的复杂性封装。
原文地址:https://www.cnblogs.com/xiyuanMore/p/10241827.html
.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com
本文分享自微信公众号 - dotNET跨平台(opendotnet)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。