聚合Aggregate

什么是聚合:

聚合是一个更大的封装单位,而不仅仅是一个类。每个事物的范围限定在单个聚合内。聚合组件的使用期被界限在整个聚合的生命周期中。
具体的,一个聚合将会处理命令,请求事件,并在其中封装一个状态模型,使其能够实现所需的命令验证,从而维护聚合的不变量(即业务规则)

聚合和聚合根之间有什么区别:

聚合形成对象关系的树或者图。而聚合根是树的“顶”,它总体上说明了聚合并且代表了剩余部分,它很重要因为他是所有通信的地方。

我知道聚合是事务边界,但我真的需要在同一个事务中事务更新两个聚合。我该怎么办?

我们应该重新思考如下:
   ①你的聚合边界
   ②每个聚合的自责
   ③你怎么样才可以侥幸逃脱掉在读的一端或者在一个saga中
   ④你的领域的真实的非功能性的需求
   如果你写了一个解决方案,但是有两个或者多个的聚合以事务的方式耦合了,那么就说明你没有理解聚合

为什么使用GUID作为ID是一个很好的做法?

因为它们(合理)全局唯一,并且可以由服务器或客户端生成。

如何获取新创建的聚合的ID?

这是一个重要的见解,客户端可以生成自己的ID。
如果客户端生成了GUID并且将其放在创建聚合的命令中,这不是一个问题。否则,你需要从适当的读取端进行轮询,其中ID将以最终一致的时间框架出现。显然,这种是比在一开始就生成的方式要
脆弱的多的

我们应该允许聚合间的引用吗?

从真实的“内存引用”的意义而言,当然是不可以的
在写方面,一个真实的从一个聚合到另外一个聚合的内存引用是不对和禁止的。因为聚合的定义不允许到达他自己的外部(如果允许的话,那么意味着聚合不再是事务边界,意味着我可以不再去
思考维护其不变量的能力,他亦阻止了聚合的分隔)
使用字符串标识符引用另一个聚合是可以的。在写方面是没有用的(因为标识符必须被视为不透明的值,因此聚合不能到达自身之外)。读的一端可能自由的使用这些信息来进行有趣的相关性

如何在一组聚合中验证命令?

这是一种再也无法通过聚合进行查询了的常见的副作用,有几个答案:
①客户端验证
②使用读的一端
③使用saga
④如果那些完全不切实际,那么这就该考虑是否是聚合的边界不对

如何保证整体的引用完整性?

你现在仍在思考外来的关系引用,而不是聚合。看最后的那个问题。当然,记住仅仅因为是两个表的关系设计不易任何方式表明他们是两个聚合。聚合设计是不同的

如何确保新创建的用户具有唯一的用户名?

这是一个常见的问题,因为我们明确地不会在写方面执行交叉聚合操作。但是,我们有很多选择:
①创建一个已经分配了用户名字的读取端。让客户端可以交互式的以键入用户名的方式查询读取端。
②创建一个响应式的saga来标记和停用那些不过是以用户名的读本创建的账户(无论是否是极端巧合或者恶意的或者由于客户的错误)
③如果最终的一致性不够快,那么可以考虑在写的一端添加一个小的本地读取方面得标。确保聚合的食物插入该表

当我下订单时,如何验证客户ID是否真的存在?

假设客户和订单都聚集在这里,很明显,订单的聚合是不能验证这个的,因为这意味着到达了聚合之外了
在事实之后检查,在一个记录了‘broken’订单的saga或者仅仅在一个读取端。毕竟,订单的最重要的事实完全的记录它,大概任何关于订单的收件人的有趣的数据将会被复制到订单聚合中
(引用到用户去访问其地址是坏的设计,订单总是用来提供一个特定的地址,无论是否在未来客户改变他们的地址)
能够使用那些被记录在破损订单的数据意味着你有机会来拯救它,扭转局面---这使得比下列命令更有意义,因为违反外键约束!

如何使用单个命令更新一组聚合?

单一的命令是不能操作一组聚合的。
首先,问问自己你是不是真的需要一个命令更新多个聚合,是什么情况导致这个需求。
然而,你是可以这么做的。允许一种新的“批量命令”。在概念上包含你想要发布的命令以及一组您要发布的聚合(指定或明确指定)。写入段不够强大到处理这种批量操作,但是它可以创建相应
的”批量事件”。一个saga捕获这个事件,并在每个指定的聚合上执行命令。当命令失败的时候,saga可以视情况调用rollback或者发送一封邮件。
这种方法有一些优点:我们将批量操作的意图存储在事件存储中。saga自动回滚或等效。
尽管如此,不得不诉诸于此解决方案,这表明您的聚合的总体边界并不正确。你可能想考虑改变你的聚合边界,而不是为此建立一个saga。

什么是分片?

一种在多个写入端节点上分发大量聚合的方式。我们可以很容易地分解聚合,因为它们完全是自立的。
我们可以很容易地分割聚合,因为它们没有任何外部引用。

聚合可以将事件发送到另一个聚合?

不可以
你的聚合和命令处理器这些因素代表性的早已在代码中使这个想法无法表达,但是有一个更深层次的哲学原因:
    回去重新读第一个问题“what's an aggregate?”
如果你设法规避命令处理程序,将事件推向另外一个聚合,那么你将会失去聚合的参与验证的变化的机会。这就是为什么我们仅仅允许聚合器上的命令处理程序验证的命令创建事件。

我能从我的聚合中调用一个读取端吗??

不可以

在CQRS系统中我们么发送email

在聚合之外的时间处理器,不要早命令处理程序中执行此操作,就像这个事件由于丢掉了与其他命令竞争而不会被持久化,所以email将会在一个虚假的前提下被发送。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


什么是设计模式一套被反复使用、多数人知晓的、经过分类编目的、代码 设计经验 的总结;使用设计模式是为了 可重用 代码、让代码 更容易 被他人理解、保证代码 可靠性;设计模式使代码编制  真正工程化;设计模式使软件工程的 基石脉络, 如同大厦的结构一样;并不直接用来完成代码的编写,而是 描述 在各种不同情况下,要怎么解决问题的一种方案;能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免引
单一职责原则定义(Single Responsibility Principle,SRP)一个对象应该只包含 单一的职责,并且该职责被完整地封装在一个类中。Every  Object should have  a single responsibility, and that responsibility should be entirely encapsulated by t
动态代理和CGLib代理分不清吗,看看这篇文章,写的非常好,强烈推荐。原文截图*************************************************************************************************************************原文文本************
适配器模式将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的类可以相互合作。
策略模式定义了一系列算法族,并封装在类中,它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
设计模式讲的是如何编写可扩展、可维护、可读的高质量代码,它是针对软件开发中经常遇到的一些设计问题,总结出来的一套通用的解决方案。
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
迭代器模式提供了一种方法,用于遍历集合对象中的元素,而又不暴露其内部的细节。
外观模式又叫门面模式,它提供了一个统一的(高层)接口,用来访问子系统中的一群接口,使得子系统更容易使用。
单例模式(Singleton Design Pattern)保证一个类只能有一个实例,并提供一个全局访问点。
组合模式可以将对象组合成树形结构来表示“整体-部分”的层次结构,使得客户可以用一致的方式处理个别对象和对象组合。
装饰者模式能够更灵活的,动态的给对象添加其它功能,而不需要修改任何现有的底层代码。
观察者模式(Observer Design Pattern)定义了对象之间的一对多依赖,当对象状态改变的时候,所有依赖者都会自动收到通知。
代理模式为对象提供一个代理,来控制对该对象的访问。代理模式在不改变原始类代码的情况下,通过引入代理类来给原始类附加功能。
工厂模式(Factory Design Pattern)可细分为三种,分别是简单工厂,工厂方法和抽象工厂,它们都是为了更好的创建对象。
状态模式允许对象在内部状态改变时,改变它的行为,对象看起来好像改变了它的类。
命令模式将请求封装为对象,能够支持请求的排队执行、记录日志、撤销等功能。
备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。 基本介绍 **意图:**在不破坏封装性的前提下,捕获一个对象的内部状态,并在该
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为
享元模式(Flyweight Pattern)(轻量级)(共享元素)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结