谈论 DDD 问题很困难,因为每个人都需要有共同的上下文知识,这样解释和业务规则才有意义。因此,我使用支付和购物车等众所周知的概念。
在以 DDD 为中心的实现中,购物车是一个聚合根,每个购物项目都是一个域实体,每个项目的价格都可以建模为一个价值对象。
这些对象中的每一个都抽象出一些业务逻辑,因此它们不是贫乏的领域模型。例如
Price 是一个值对象,它可能包含诸如转换为不同货币、用于加法或减法的特殊逻辑(考虑四舍五入)等方法。
与 Price 类似,cart-item 也有一些特殊的方法,例如添加特定商品的数量或其颜色,但由于我们可以在我们的系统(购物车)中唯一标识它,因此它是一个实体。
最后,购物车是一个聚合根。它包含购物项目,并且可以应用可能涉及购物车项目的业务规则,例如,如果购物车中所有时间的总价格达到阈值,则将免费奖励项目添加到购物车。
但这些抽象是不够的,有时我们可能有复杂的业务规则,其中涉及多个聚合根、实体……所以在这种情况下,我们定义域服务。
下一个抽象的区别非常好。假设我们的系统想要处理一个涉及与外部世界交互的请求(发送通知,...),所以我们将外部世界抽象为接口,并在需要时提供实现(端口和适配器)。然后我们使用这些接口以及我们的聚合根......来实现我们所需的功能。
如果在我们的实现过程中,我们正在建模和实现业务逻辑(检查不变量,...),那么我们正在实现域服务,但如果不涉及业务逻辑并且我们只是在协调一些 Adpaters(端口)和域实体,聚合......那么它就是一个应用服务。
基于这些假设,我有以下建议:
但我对域服务是域模型中的类、接口还是方法以及我的聚合根/域实体将如何调用该服务感到困惑?
(业务/应用程序)服务协调/管理根/域实体,反之亦然。
如果我的聚合根需要检查电子邮件是否存在,或检查密码哈希匹配(需要调用服务/存储库来访问数据库)。我需要在域服务或应用程序服务中实现该代码吗?
如果它是一种重复出现的模式,也是您的业务逻辑的一部分,那么它应该被视为域服务。如果它不涉及业务逻辑,则它是一个应用程序服务。