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

发布于 2024-10-15 08:50:06 字数 587 浏览 12 评论 0原文

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

  1. 命令
  2. 事件
  3. DTO

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

我的动机:

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

领域事件。
域模型已经按照值对象进行操作,因此通过使用 VO 发布事件而不是将它们转换为原始类型,我们可以避免一些映射代码。我很确定在这种情况下使用 VO 是可以的。

DTO。
如果我们的查询端 DTO 可以包含值对象,则可以提供更多灵活性。例如,如果我们有 Money 对象,我们可以选择以欧元还是美元显示它,无需更改读取模型。

Let's say we have CQRS-inspired architecture, with components such as Commands, Domain Model, Domain Events, Read Model DTOs.
Of course, we can use Value Objects in our Domain Model. My question is, should they also be used in:

  1. Commands
  2. Events
  3. DTOs

I haven't seen any examples where Value Objects (VO) are used in the components mentioned above. Instead, primitive types are used. Maybe it's just the simplistic examples. After all, my understanding of VOs use in DDD is that they act as a glue for the whole application.

My motivation:

Commands.
Let's say user submits a form which contains address fields. We have Address Value Object to represent this concept. When constructing command in the client, we should validate user input anyway, and when it is well-formed, we can create Address object right there and initialize Command with it. I see no need to delegate creation of Address object to command handler.

Domain Events.
Domain Model already operates in terms of Value Objects, so by publishing events with VOs instead of converting them to primitive types, we can avoid some mapping code. I'm pretty sure it's alright to use VOs in this case.

DTOs.
If our query-side DTOs can contain Value Objects, this allows for some more flexibility. E.g., if we have Money object, we can choose whether to display it in EUR or USD, no need to change Read Model.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

海风掠过北极光 2024-10-22 08:50:06

好吧,我改变主意了。我最近一直在尝试与 VO 打交道,在观看了这个 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 所需的必要属性。

原文(供后代):

如果您询问值对象是否可以通过域模型传递给事件或通过命令传递,我并没有真正看到前者有什么大问题,尽管后者可能违反了一些聚合根作为值的“所有者”的规则。

也就是说,值对象代表颜色等概念。你没有绿色,你是否绿色。一个命令告诉你通过这个就可以了,这似乎没有什么本质上的错误。

阅读 DDD 中关于聚合根模式的章节很好地解释了实体和值对象,值得多读几遍。

Ok I've changed my mind. I have been trying to deal with VOs a bunch lately and after watching this http://www.infoq.com/presentations/Value-Objects-Dan-Bergh-Johnsson it clarified a couple of things for me.

Commands and Event are messages (and not objects, objects are data + behavior), in some respects much like DTOs, they communicate data about an event and they themselves encapsulate no behavior.

Value Objects are not like DTOs at all. They are a domain representation and they are, generally speaking, rich on behavior like all other domain representations.

Commands and Events communicate information into and out of the domain respectively, but they themselves do not encapsulate any behavior. From that perspective it seems wrong and a possibly a violation context boundaries to pass VOs inside of them.

To paraphrase Oren (though he was referring to nHibernate and WCF) "Don't send your domain across the wire".
http://ayende.com/Blog/archive/2009/05/14/the-stripper-pattern.aspx

If you want to communicate a value object, then I suggest passing the necessary attributes needed to re-construct the VO within them instead.

Original Text (for posterity):

If you are asking if Value Objects can be passed by the domain model to events or passed in by commands, I don't really see a huge problem with the former, though the latter may violate some of the rules of the aggregate root being the "owner" of values.

That said a value object represents concepts like for example a color. You don't have green, you are green or not. There seems to be nothing intrinsically wrong with a command telling you that you are green by passing this.

Reading the chapter from DDD on the Aggregate Root pattern explains Entities and Value Objects quite well and is worth reading over a few times.

忱杏 2024-10-22 08:50:06

我说这是一个坏主意。

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

想象一下,您让一个事件包含一个 VO。您的域的更改需要您更改该 VO。现在,您已将自己陷入困境,您的事件也被迫进行更改,对于其所属的任何命令或 DTO 也是如此。

这是要避免的。

使用 DTO 和/或原语。映射它们(AutoMapper 使其只需 1 行即可完成)。

I say it's a bad idea.

There's a reason we don't do the same with entities - to avoid coupling other parts of the system to the domain (in the wrong places). The same is true for Value Objects, the only difference between value objects and entities is lifetime and ownership - these differences do not affect how we should and should not couple to them.

Imagine that you make an event contain a VO. A change in your domain requires you to change that VO. You've now boxed yourself into a corner where your event is also forced to change, ditto for any Commands or DTO's it's a part of.

This is to be avoided.

Use DTO's and/or primitives. Map them (AutoMapper makes it a 1-line deal).

倾听心声的旋律 2024-10-22 08:50:06

与其他答案类似,在 SOA 中,这会破坏服务的封装,因为域现在正在泄漏。

Similar to other answers, in SOA this would break encapsulation of the service as the domain is now leaking out.

維他命╮ 2024-10-22 08:50:06

根据 干净代码,您的 DTO 是数据结构(只是添加另一个术语) ,而值对象是对象。区别在于对象可以有行为。将数据结构与对象混合通常是一个非常糟糕的主意,因为很难维护所获得的混合。

我也觉得从架构角度将价值对象放入 DTO 是不对的。值对象位于域模型内部,而您提到的 DTO 正在定义模型的接口。我们通常构建一个接口来将外部世界与事物内部解耦。因此,在当前情况下,我们添加了 DTO,以将外部世界与值对象(以及其他模型相关的内容)分离。之后向界面添加值对象是疯狂的。

所以您还没有遇到这个解决方案,因为它是一种反模式。

According to Clean Code your DTOs are data structures (just to add another term), while value objects are objects. The difference that objects can have behavior. Mixing data structures with objects is generally a very bad idea, because it will be hard to maintain the hybrid you get.

I don't feel right to put value objects to DTOs from an architecture perspective as well. The value objects are inside of the domain model while the DTOs you mentioned are defining the interface of the model. We usually build an interface to decouple the outside world from the inside of something. So in the current case we added DTOs to decouple the outside world from the value objects (and other model related stuff). After that adding value objects to the interface is crazy.

So you haven't met this solution yet because it is an anti-pattern.

素年丶 2024-10-22 08:50:06

值对象是或至少应该是不可变的。一旦使用值实例化,该值在对象的整个生命周期中将永远不会改变。因此,将 VO 作为数据传递给 DTO(例如事件)应该不是问题,因为您所能做的就是获取它们的值。它们的值最多采用不同的表示形式,例如 toString(),而不是原始的 getValue(),后者可能返回整数或任何值。

Value Objects are or at least should be immutable. Once instantiated with a value that value will never change throughout the lifetime of the object. Thus, passing VOs as data to DTOs (such as Events) should not be an issue since all you can do with them is get their value. At the most their value in a differing representation such as toString() as opposed to an original getValue() which might return an integer or whatever the value is.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文