CQRS中的值对象 - 在哪里使用

dri*_*kin 36 domain-driven-design dto value-objects cqrs

假设我们拥有受CQRS启发的架构,其中包括命令,域模型,域事件,读取模型DTO等组件.
当然,我们可以在域模型中使用值对象.我的问题是,它们是否也应用于:

  1. 命令
  2. 活动
  3. 的DTO

我没有看到任何在上述组件中使用Value Objects(VO)的示例.相反,使用原始类型.也许这只是简单的例子.毕竟,我对DDD中使用VO的理解是它们可以作为整个应用程序的粘合剂.

我的动机:

命令.
假设用户提交包含地址字段的表单.我们有Address Value Object来表示这个概念.在客户端构造命令时,我们应该验证用户输入,当它格式正确时,我们可以在那里创建Address对象并用它初始化Command.我认为不需要将Address对象的创建委托给命令处理程序.

域事件.
域模型已经在值对象方面运行,因此通过使用VO发布事件而不是将它们转换为基本类型,我们可以避免使用某些映射代码.我很确定在这种情况下使用VO是可以的.

DTO的.
如果我们的查询端DTO可以包含值对象,则可以提供更多灵活性.例如,如果我们有Money对象,我们可以选择是以EUR还是USD显示,不需要更改Read Model.

Chr*_*ola 26

好的,我改变了主意.我一直在试图最近处理虚拟组织一堆,看此之后http://www.infoq.com/presentations/Value-Objects-Dan-Bergh-Johnsson它澄清了一些事情对我来说.

命令和事件是消息(而不是对象,对象是数据+行为),在某些方面很像DTO,它们传递有关事件的数据,它们自己封装没有行为.

价值对象根本不像DTO.它们是域代表,一般来说,它们像所有其他域表示一样富有行为.

命令和事件分别将信息传入和传出域,但它们本身并不封装任何行为.从这个角度看,它似乎是错误的,并且可能是一个违反上下文边界来传递它们内部的VO.

用Oren来解释(虽然他指的是nHibernate和WCF)"不要通过网络发送你的域名". http://ayende.com/Blog/archive/2009/05/14/the-stripper-pattern.aspx

如果你想传达一个值对象,那么我建议传递在其中重新构造VO所需的必要属性.

原文(后代):

如果你问的是Value Objects是否可以通过域模型传递给事件或者通过命令传入,我实际上并没有看到前者的巨大问题,尽管后者可能会违反聚合根的一些规则.价值观的"所有者".

也就是说,值对象表示诸如颜色之类的概念.你不必绿色的,你绿色或没有.通过这个命令告诉你你是绿色的命令似乎没有什么本质上的错误.

从聚合根模式下的DDD中读取章节可以很好地解释实体和值对象,并且值得阅读几次.

  • "价值对象根本不像DTO.它们是一种域代表,它们像所有其他域表示一样富有行为." 我非常不同意后一部分.虽然它们是域的一部分(例如,定义*地址*是什么),但它们意味着是一次性的,并且没有任何附加于它们的行为.这就是为什么它们通常是不可改变的,以防止你想要弄乱你的VO. (6认同)
  • 不变性和行为不是相互排斥的概念.值对象,例如`Money`或`DateRange`肯定会根据它所代表的域概念提供一些相关的功能和逻辑.如果它只是数据,内置的基本类型就足够了.请参阅:http://martinfowler.com/eaaCatalog/valueObject.html (2认同)

que*_*rin 5

我说这是个坏主意。

我们不对实体做同样的事情是有原因的 - 避免将系统的其他部分耦合到域(在错误的地方)。值对象也是如此,值对象和实体之间的唯一区别是生命周期和所有权——这些差异不会影响我们应该和不应该如何耦合它们。

想象一下,您让一个事件包含一个 VO。您域的更改要求您更改该 VO。您现在已经将自己困在一个角落里,您的事件也被迫更改,任何命令或 DTO 也是如此。

这是要避免的。

使用 DTO 和/或原语。映射它们(AutoMapper 使其成为单线交易)。

  • 好吧,那些 VO 不会只属于领域模型。它们将是所有系统组件(如任何人都可以引用的 MyApp.Core 程序集)的共享知识。只要那里的概念稳定,甚至没有重大变化,我想这应该没问题。Ofc,如果我们使用事件溯源,这会使我们的代码与不再使用但属于旧事件一部分的遗留概念混淆。所以这是我能想到的一个缺点。但是,跨应用程序拥有一个共享概念(如货币、货币、速度)模块的想法对我来说仍然很诱人。 (2认同)