我正在成为DDD的忠实粉丝。所以,我正在考虑将它正确地应用到我开发的当前系统中。
假设我们有两个聚合根:Order
和User
。 Order
有两个属性,引用User
:owner
和contractor
。所有者创建了Order
,承包商履行了它。
业主可以评估承包商履行Order
的质量。我们有一个Feedback
实体,连接到Order
,包含评级。
现在,User
对象包含每个用户在其履行的订单中的平均评分。这部分让我感到困惑。
User
评分不仅仅是一个静态属性,实际上是Feedbacks
中所有评分的平均值。在Order
附加Feedback
时,它会被更改(需要重新计算)。
目前我有一些封装域逻辑的服务:OrderService
和UserService
(我知道这实际上不符合DDD,但我稍后会重构)。当OrderService收到将反馈附加到订单的命令时,它会发出OrderFeedbackAttachedEvent
,UserService会侦听以重新计算用户评级。
对我不满意的是,关于Order聚合根的知识现在已泄露到UserService中。而且我没有看到逃避它的方法。我开始认为应该有一些模式来处理这种情况。
评级似乎是用户的完美属性。但事实上,它不是一个静态的,持久的价值,而是基于其他对象数据计算的东西,让我怀疑。
评级本身也不是一个实体。它既不是价值对象。我想知道,在DDD中它是什么?如何在不牺牲性能和易用性的情况下对系统中的评级(或任何其他可计算值)进行建模?
答案 0 :(得分:7)
看起来你可能至少有2个分离的有界上下文:一个用于排序,另一个用于反馈。
Aknowleging Bounded Contexts允许你看到同一物理事物的不同抽象:在“订单”上下文中,Order似乎是一个合法的Aggregate,但它可能是“反馈”BC中的一个Value Object,它会在那里持有订单ID(该值来自BC通过事件的订单)。
以下是提案:
使用此模型,您可以在承包商汇总的事件处理程序中处理反馈汇总中的“FeedbackEmitted”事件时计算承包商的平均评级
希望这会有所帮助:)
答案 1 :(得分:2)
公平地说,从另一个AR或另一个BC发出的事件不是泄漏。在我看来,User
AR处理OrderFeedbackGiven
事件没有问题。如果Feedback
VO是事件的一部分,那么客户端不需要依赖任何其他事件来处理事件。有一个反馈有限的上下文可能会更清晰,但我不会为此实现一个完整的BC,否则你会爆发微型BC ......
我很担心这一事实,在给出反馈后,所有 必须汇总反馈以计算用户评级。这创造了一个 从用户到订单的依赖(调用订单存储库以获取 当事件被捕获时,来自用户服务的评级)。这样可以,做什么 你觉得呢?
我认为如果你那样做并不重要。应用程序服务层整体上取决于域层。但是,由于您可以计算moving cumulative average。
,因此根本不需要这样做 E.g。其中this.ordersFeedbackAvg
是MovingAvg
值对象,用于跟踪平均值以及计算的数据点数。
when(OrderFeedbackGiven feedback) {
this.ordersFeedbackAvg = this.ordersFeedbackAvg.cumulate(feedback.mark);
}