我正在努力思考如何正确地使用存储库模式。聚合根的核心概念不断出现。当我在web和Stack Overflow上搜索什么是聚合根时,我一直在寻找关于聚合根的讨论,以及指向应该包含基本定义的页面的死链接。

在存储库模式的上下文中,什么是聚合根?


当前回答

聚合根是一个简单概念的复杂名称。


一般的想法

设计良好的类图封装了它的内部结构。访问该结构的点称为聚合根。

解决方案的内部结构可能非常复杂,但是这个层次结构的用户将只使用root. dosomethingwherehasbusinessmeaning()。


例子

检查这个简单的类层次结构

你想怎样驾驶你的车?选择更好的API

选项A(它只是以某种方式工作):

car.ride();

选项B(用户可以访问类内部内容):

if(car.getTires().getUsageLevel()< Car.ACCEPTABLE_TIRE_USAGE)
    for (Wheel w: car:getWheels()){
        w.spin();
    }
}

如果你认为选择A更好,那么恭喜你。你得到了根集合背后的主要原因。


聚合根封装多个类。您只能通过主对象操作整个层次结构。

其他回答

在存储库模式上下文中,聚合根是客户端代码从存储库加载的唯一对象。

存储库封装了对子对象的访问——从调用者的角度来看,它会自动加载它们,要么在加载根对象的同时加载,要么在实际需要它们的时候加载(与惰性加载一样)。

例如,您可能有一个Order对象,它封装了多个LineItem对象上的操作。您的客户端代码永远不会直接加载LineItem对象,只加载包含它们的Order,这将是域的该部分的聚合根。

聚合是指某物的集合。 根就像树的顶部节点,从那里我们可以访问网页文档中的<html>节点。 博客类比,一个用户可以有很多帖子,每个帖子可以有很多评论。因此,如果我们获取任何用户,那么它可以作为根访问所有相关的帖子和这些帖子的进一步评论。这些统称为集合或聚合

来自埃文斯DDD:

AGGREGATE是一组相关联的对象,我们将其作为一个单元来处理数据更改。每个AGGREGATE都有一个根和一个边界。边界定义了聚合中的内容。根是聚合中包含的单个特定ENTITY。

And:

根是AGGREGATE中唯一允许外部对象持有对[]引用的成员。

这意味着聚合根是唯一可以从存储库加载的对象。

一个例子是一个包含Customer实体和Address实体的模型。我们永远不会直接从模型中访问Address实体,因为如果没有关联的Customer上下文,它就没有意义。所以我们可以说Customer和Address一起构成了一个集合,而Customer是一个集合根。

在另一个世界中,在事件源中,聚合(根)是一个不同的概念。 事件源可能与CQRS、DDD等一起遇到。

在事件源中,聚合是一个对象,其状态(字段)没有映射到数据库中的记录,因为我们习惯于在SQL/JPA世界中思考。

不是一组相关的实体。

它是一组相关的记录,类似于历史表。

GiftCard。amount是GiftCard Aggregate中的一个字段,但是这个字段被映射到所有创建的事件,比如卡兑换(从卡中取钱)。

因此,聚合的数据源不是数据库中的记录,而是为特定聚合创建的事件的完整列表。我们说我们的事件源聚合。

现在我们可以问问自己,这是怎么做到的?谁在聚合这些事件,我们仍然使用一个字段,例如giftcard。amount?我们可能期望这个数量是一个集合,而不是一个大十进制类型。

是事件来源引擎,负责工作,它可能只是按创建顺序重播所有事件。但这超出了本线程的范围。

如果您采用数据库优先的方法,则聚合根通常是1-多关系中第一边的表。

最常见的例子是Person。每个人都有许多地址、一张或多张工资单、发票、CRM条目等。并非总是如此,但有9/10次都是如此。

我们目前在一个电子商务平台上工作,我们基本上有两个聚合根:

客户 卖家

客户提供联系信息,我们将交易分配给他们,交易获得行项目,等等。

卖家出售产品,有联系人,关于我们的页面,特别优惠等。

这些分别由Customer和Seller存储库负责。