- 实体应该是私有的聚合
是的。我不认为这是一个问题。继续阅读以了解原因。
- 我们需要一个只读副本值对象来公开来自实体的信息(至少让存储库能够读取它以便
例如,保存到数据库)
没有。使您的聚合返回需要持久化和/或需要在聚合的每个方法的事件中引发的数据。
原始示例。现实世界需要更细粒度的响应,也许performMove 函数需要使用game.performMove 的输出来为persistence 和eventPublisher 构建propper 结构:
public void performMove(String gameId, String playerId, Move move) {
Game game = this.gameRepository.load(gameId); //Game is the AR
List<event> events = game.performMove(playerId, move); //Do something
persistence.apply(events) //events contains ID's of entities so the persistence is able to apply the event and save changes usign the ID's and changed data wich comes in the event too.
this.eventPublisher.publish(events); //notify that something happens to the rest of the system
}
对内部实体执行相同操作。让实体返回由于其方法调用(包括其 ID)而更改的数据,在 AR 中捕获此数据并为持久性和 eventPublisher 构建适当的输出。这样,您甚至不需要向 AR 公开带有实体 ID 的公共只读属性,而 AR 也不需要向应用程序服务公开其内部数据。这是摆脱 Getter/Setters 包对象的方法。
- 我们在实体上拥有的方法在 Aggregate 上重复(反之亦然,我们在 Aggregate 上必须拥有的处理实体的方法
在实体上重复)
有时,要检查和应用的业务规则仅属于一个实体,其内部状态和 AR 只是充当网关。没关系,但如果你发现这种模式太多,那么这表明 AR 设计有误。也许内部实体应该是 AR 而不是内部实体,也许您需要将 AR 拆分为多个 AR(其中一个是旧的 ner 实体),等等......不要害怕拥有只有一个的类或两种方法。
回应dee zg cmets:
persistance.apply(events) 究竟做了什么?它能拯救整个
仅聚合还是实体?
两者都没有。聚合和实体是领域概念,而不是持久性概念;您可以拥有不需要一对一匹配您的域概念的文档存储、列存储、关系等。您不会从持久性中读取聚合和实体;您使用从持久性中读取的数据在内存中构建聚合和实体。聚合本身不需要持久化,这只是一个可能的实现细节。请记住,聚合只是一种组织业务规则的构造,它并不意味着是状态的表示。
您的事件具有上下文(用户意图)和已更改的数据(以及在持久性中识别事物所需的 ID),因此在知道的持久层中编写 apply 函数非常容易,即在关系数据库的情况下执行什么 sql 指令,执行什么以应用事件并持久化更改。
您能否提供示例何时以及为什么更好(甚至
不可避免?)使用子实体而不是单独的 AR 引用
其 Id 作为值对象?
您为什么要设计一个具有状态和行为的类并对其建模?
进行抽象、封装、复用等基本SOLID设计。如果实体具有确保操作的域规则和不变量所需的一切,那么该实体就是该操作的 AR。如果您需要实体无法完成的额外域规则检查(即实体没有足够的内部状态来完成检查或不自然地适合实体和代表什么),那么您必须重新设计;有时可能是对执行额外域规则检查的聚合建模并将其他域规则检查委托给内部实体,有时可能会更改实体以包含新事物。它过于依赖领域上下文,所以我不能说有一个固定的重新设计策略。
请记住,您不会在代码中对聚合和实体进行建模。您只需对具有行为的类进行建模,以检查域规则以及执行该检查和响应更改所需的状态。这些类可以充当不同操作的聚合或实体。这些术语仅用于帮助沟通和理解类在每个操作上下文中的作用。当然,您可能会遇到操作不适合实体的情况,您可以使用 V.O. 对聚合进行建模。持久性 ID 并且没问题(遗憾的是,在 DDD 中,在不了解域上下文的情况下,默认情况下几乎所有内容都可以)。
你想从比我解释得更好的人那里得到更多启发吗? (不是以英语为母语是这些复杂问题的障碍)看看这里:
https://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-1
http://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-2
http://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-3