如何在 DDD 中正确设计模型的计算字段?

How to properly design model's calculated fields in DDD?

我正在成为 DDD 的超级粉丝。所以,我正在考虑将它正确地应用到我当前开发的系统中。

假设我们有两个聚合根:OrderUserOrder 有两个属性,引用 Userownercontractor。所有者创建了一个 Order,承包商完成了它。

业主可以对承包商履行 Order 的质量进行评分。所以我们有一个 Feedback 实体,连接到 Order,包含评级。

现在,User 对象包含每个用户对其完成的订单的平均评分。这部分让我有点困惑。

User 评分不仅是静态的 属性,而且实际上是 Feedbacks 中所有评分的平均值。并且在 Order 附加了 Feedback 的那一刻它被改变了(需要重新计算)。

目前我有一些服务封装了领域逻辑:OrderServiceUserService(我知道这实际上不符合DDD,但我稍后会重构它)。当 OrderService 收到将反馈附加到订单的命令时,它会发出 OrderFeedbackAttachedEvent UserService 侦听以重新计算用户评分。

令我不满意的是关于Order聚合根的知识现在泄露到UserService中了。而且我看不到逃避它的方法。我开始认为应该有一些模式来处理这种情况。

用户的评分似乎很完美属性。但它不是一个静态的、持久的值,而是根据其他对象数据计算出来的东西,这一事实让我怀疑。

评级本身也不是一个实体。它也不是一个值对象。我想知道 DDD 中的它是什么?我如何在不牺牲性能和易用性的情况下在我的系统中对评分(或任何其他可计算值)进行建模?

看来您可能至少有 2 个独立的限界上下文:一个用于订购,另一个用于反馈。

了解限界上下文可以让您看到同一物理事物的不同抽象:在 "orders" 上下文中,Order 似乎是一个合法的聚合,但在 [=25= 中它可能是一个值对象] BC,它将保存一个订单 ID(该值通过事件来自订单 BC)。

这是一个提议:

使用此模型,您可以在承包商聚合的事件处理程序中处理来自反馈聚合的 "FeedbackEmitted" 事件时计算承包商的平均评分

希望这对您有所帮助:)

公平地说,从另一个 AR 或另一个 BC 发出的事件不是泄漏。我认为 User AR 处理 OrderFeedbackGiven 事件没有问题。如果 Feedback VO 是事件的一部分,那么客户端不需要依赖任何其他东西来处理事件。有一个反馈限界上下文可能会更干净,但我不会为此实施一个完整的 BC,否则你将有一个微型 BC 的爆炸......

I am worried by the fact, that after feedback was given, all feedbacks must be aggregated to calculate user rating. That creates a dependency from user to order (calling order repository to fetch rating from user service, when event was caught). Is this ok, what do you think?

我认为如果你那样做了也没关系。应用服务层整体上依赖于领域层。但是,根本不需要这样做,因为您可以计算 moving cumulative average.

例如其中 this.ordersFeedbackAvg 是一个 MovingAvg 值对象,用于跟踪平均值及其计算出的数据点数。

when(OrderFeedbackGiven feedback) { this.ordersFeedbackAvg = this.ordersFeedbackAvg.cumulate(feedback.mark); }