Domain driven design CQR中的值对象-在何处使用

Domain driven design CQR中的值对象-在何处使用,domain-driven-design,dto,cqrs,value-objects,Domain Driven Design,Dto,Cqrs,Value Objects,假设我们有CQR启发的体系结构,包括命令、域模型、域事件、读取模型DTO等组件。 当然,我们可以在域模型中使用值对象。我的问题是,它们是否也应用于: 命令 事件 DTOs 我没有看到在上述组件中使用值对象(VO)的任何示例。而是使用基本类型。也许这只是一些简单化的例子。毕竟,我对DDD中VOs使用的理解是,它们充当整个应用程序的粘合剂 我的动机: 命令。 假设用户提交了一个包含地址字段的表单。我们有地址值对象来表示这个概念。在客户端构造命令时,我们无论如何都应该验证用户输入,当它格式正确时,我们

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

  • 命令
  • 事件
  • DTOs
  • 我没有看到在上述组件中使用值对象(VO)的任何示例。而是使用基本类型。也许这只是一些简单化的例子。毕竟,我对DDD中VOs使用的理解是,它们充当整个应用程序的粘合剂

    我的动机:

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

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

    DTOs.

    如果我们的查询端DTO可以包含值对象,这将允许更大的灵活性。例如,如果我们有货币对象,我们可以选择是否以欧元或美元显示,无需更改读取模式

    我说这是个坏主意

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

    假设您使一个事件包含一个VO。域中的更改要求您更改该VO。现在,您已经将自己禁锢在一个角落里,您的事件也被迫改变,这与它所属的任何命令或DTO都是一样的

    这是必须避免的


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

    好的,我改变了主意。最近我一直在尝试和VOs打交道,在看了这部电影之后,我澄清了一些事情

    命令和事件是消息(而不是对象,对象是数据+行为),在某些方面很像DTO,它们传递有关事件的数据,并且它们本身不封装任何行为


    值对象与DTO完全不同。它们是一种域表示,一般来说,它们的行为与所有其他域表示一样丰富

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

    套用Oren(尽管他指的是nHibernate和WCF)“不要通过网络发送你的域名”。

    如果您想要传递一个值对象,那么我建议传递必要的属性,以便在它们内部重新构造VO

    原文(为子孙后代):

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

    也就是说,值对象表示诸如颜色之类的概念。你没有绿色,你是不是绿色。如果一个命令告诉您通过传递这个命令是绿色的,那么它似乎没有本质上的错误


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

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

    根据DTO,是数据结构(只是添加另一个术语),而值对象是对象。对象可能具有的行为差异。将数据结构与对象混合通常是一个非常糟糕的主意,因为很难维持您得到的混合

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


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

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

    好吧,这些VO不会只属于域模型。它们将是所有系统组件(如MyApp.Core assembly,任何人都可以引用)的共享知识。只要有稳定的概念,甚至没有突破性的变化,我想这应该是好的。Ofc,如果我们使用事件源,这将使我们的代码与遗留概念混淆,这些概念不再使用,而是旧事件的一部分。所以这是我能想到的一个缺点。不过,在整个应用程序中拥有一个共享概念(如货币、货币、速度)模块的想法对我来说还是很有诱惑力