【问题标题】:Passing CQRS commands directly to Domain objects将 CQRS 命令直接传递给域对象
【发布时间】:2015-08-06 16:55:44
【问题描述】:

~TLDR:我正在为我的一个大型项目实施 CQRS + DDD 解决方案,而且,我想知道我的命令处理程序是否有任何真正的原因不能直接将命令对象分派到我的聚合中,在少数情况下,命令对象的数据丰富?我找不到任何具体原因说明这会是一种反模式,我也找不到任何关于这种设计的非常详细的意见。

背景:我以前实现过 CQRS 系统,也实现过 DDD 应用程序,但从未在适当的 Eric Evans 风格的域驱动应用程序中实现 CQRS + DDD。所以我问是因为我不想滥用我的聚合,并从长远来看伤害我的应用程序。

一个包含大量数据的命令对象的示例是一个注册命令,它包含 8 个以上的字段(名字、姓氏、首选名称、dob、标题、用户名、密码、部门等)。在我的 Aggregate 上创建一个有 8 个参数的方法感觉非常尴尬,以及使用某种 dto 的替代解决方案,并让我的处理程序将命令映射到 dto - 自动使用 automapper 或内联 - 似乎是不必要的非增值抽象。

我还可以看到未来的用例,其中命令可能是数据丰富的(命令不会占很大比例,但仍然会有一些),所以我想纠正这个看似微不足道的方面开始。

【问题讨论】:

  • 据我记得,DDD 并没有具体说明如何实现域模型,但 CQRS 可以。这里没有冲突。关于简单的命令对象,您是如何将它们传递给聚合的?我猜你有一个两者都依赖的抽象/接口。
  • 我通过参数将命令数据(不是实际的命令对象)传递给聚合。该命令由加载聚合的处理程序接收,并通过适当设计的方法简单地将其传递给它。通常它只是一个或几个参数,这是我喜欢的方式,因为我相信设计良好的聚合应该具有需要很少参数的方法。否则它可能会以某种方式违反 SRP。但是,有一些可能需要大量参数的边缘情况。
  • 您是否考虑将整个命令对象传递给聚合?看起来很简单,这里没有缺点。
  • 这实际上是我的问题:我想知道我的命令处理程序是否有任何真正的原因不能直接将命令对象分派到我的聚合中跨度>
  • @neleus CQRS 是一个实现细节,所以我宁愿避免用这个概念污染域。

标签: domain-driven-design cqrs


【解决方案1】:

命令对象通常以原始类型表示,而聚合方法签名将以域概念表示。

您没有立即意识到这一事实可能意味着您错过了很多在您的领域中明确表达隐含概念的机会。

“一个注册命令,包含 8 个以上的字段(名字、姓氏、 首选姓名、出生日期、职务、用户名、密码、部门等)"

您应该感到震惊的是firstnamelastname 绝对可以形成一个有意义的整体,例如new FullName(firstname, lastname),我敢肯定还有很多其他情况可以或应该使用值对象 (VO)在您的域中...UsernamePassword 等?使用 VO 对一起变化的事物进行建模将更好地描述您的模型并减少您必须传递的参数数量。

因此,这使得命令对象不能作为聚合方法参数。如果你走这条路,你肯定会错过模特机会。

【讨论】:

  • 这很有意义。感谢您的回答,以及对为什么的明确解释
【解决方案2】:

同意@plalx。

将命令作为聚合方法参数可能会导致聚合内部的映射代码过多:将原始类型映射到域对象,最好放在域对象之外。

但对于更简单的项目,我认为它是一个很好的入门。

在注册案例中,限界上下文通常是一个支持域,复杂性通常来自外部集成(电子邮件通知、注册社交帐户等)。在这种情况下,我认为有界上下文集成比内部模型更重要。因此,将命令作为聚合方法参数可能是完成工作的快速开始,并节省您专注于核心领域的时间。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多