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

Vla*_*sny 7 architecture design-patterns domain-driven-design

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

假设我们有两个聚合根:OrderUser.Order有两个属性,引用User:ownercontractor.业主创建了一个Order承包商来实现它.

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

现在,Userobject包含每个用户在其完成的订单中的平均评级.而这一部分让我感到困惑.

User评级不仅仅是一个静态属性,而且实际上是所有评级的平均值Feedbacks.它改变了(需要重新计算)此刻的OrderFeedback连接.

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

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

评级似乎是用户的完美属性.但事实上,它不是一个静态的,持久的价值,而是基于其他对象数据计算的东西,让我怀疑.

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

Meh*_*di. 7

看来你可能至少有2个分离的有界上下文:一个用于排序,另一个用于反馈.

Aknowleging Bounded Contexts允许您查看同一物理事物的不同抽象:在"订单"上下文中,Order似乎是一个合法的Aggregate,但它可能是"反馈"BC中的一个值对象,它将保存一个订单id(该值来自BC通过事件的顺序).

这是一个提议:

在此输入图像描述 在此输入图像描述

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

希望这可以帮助 :)

  • @DavidOsborne:我使用了http://www.plantuml.com/plantuml/该语法记录在http://plantuml.com/ (5认同)

pla*_*alx 2

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

我担心的是,在给出反馈后,必须汇总所有反馈来计算用户评分。这会创建从用户到订单的依赖关系(当捕获事件时,调用订单存储库以从用户服务获取评级)。这样可以吗,你觉得怎么样?

我想如果你这么做了也没关系。应用服务层作为一个整体依赖于领域层。但是,根本不需要这样做,因为您可以计算移动累积平均值

例如,Wherethis.ordersFeedbackAvg是一个MovingAvg值对象,用于跟踪平均值以及计算平均值的数据点数量。

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