domain-driven-design - 域服务为何必须将域对象用作参数和返回值?

  显示原文与译文双语对照的内容

当操作不属于任何实体或者值对象,而是将行为强制为一个对象时,我们应该创建一个域服务。

应该根据域模型的其他元素来定义服务的接口。 换句话说,服务shold的参数和返回值是域对象

1 ) 为什么/必须域服务将域对象用作参数和返回值?

b ) 为什么不要使用实体和值对象的方法来使用域对象作为参数和返回值? 为什么这种约束只放在服务上?

谢谢你

EULERFX:

1 )

这两个约束都促进了不变性和函数风格

a ) 这两个约束如何促进不变性?

b ) 功能样式?

c ) 使用( 因为它可能不可能总是使用力) 强制服务使用域对象作为参数和返回值,即使服务( IE 行为) 接受/返回非域对象。

2 )

实体和值对象构成更原始类型来形成复杂类型,某些行为可能依赖于原始参数。

它的内在特征是域实体/价值对象的本质特征,在大多数情况下,它们的行为是在基本类型的基础上操作的? 如果是,那么在大多数情况下,这就是在域对象中发现的这种内在特性,但是在领域服务中很少?

更新:

这两个约束如何促进不变性?

这个想法是,域服务不会改变状态,并且所有状态更改都通过参数显式地。

a ) 不改变自身的状态或者对象的某些域状态? 因为域服务应该是无状态的,所以我假设你是指它不应该改变? 换句话说,通过确保将要修改的任何操作都传递给它作为参数,服务可以提升用户定义的不可以变性。

b ) 但是如果不是通过服务修改的话,那么我们说域服务变异了这个状态。

c ) 是为什么变异的原因被认为是一个坏事,因为它不会促进清晰的( IE 在查看服务操作的签名时并不立即明显,但DOs将会通过操作更改它们的状态。) 。

d ) 如果域服务将作为参数修改的状态,则将它的用于更改这里事件状态的值也将作为参数。 如果是的话是因为它促进了清晰度还是。

2 ) 我仍然不明白如何使用与参数相同的返回值也会促进不可以变性?

EULERFX 3

a )

域服务可以通过返回对象的新实例而不是修改传入的对象来避免状态突变。

不是一个问题,更多的观点,但有些困难理解为什么这样的服务行为,或者 !

b )

是的,尽管在这种情况下,域对象会更好地变异自身。

重要的原因是,这种代码的执行方式集中在一个地方,如果我们需要检查它。

时间: 原作者:

a ) 这不是一个严格的约束,但提供了一定的优势。 规则背后的思想是域服务包含补充现有实体和值对象的功能。 另一个非严格约束是操作闭包,其中域服务方法的参数和返回值的类型相同。 这两种约束都促进了不可以变性和功能样式,从而减少了副作用,使代码更易于理解。

可以有一个域服务方法,该方法接受一个不是实体或者值对象的基本类型。 但是,大量使用基元类型可能会导致原始的痴迷。

b ) 不能在实体和值对象级别应用这里约束,以达到一定程度。 实体和值对象构成更原始类型来形成复杂类型,某些行为可能依赖于原始参数。 这个基本参数本身可以变成一个值对象。

更新

Just meetup,我有机会与 Vaughn Vernon的作者实现领域驱动设计设计的作者。 他同意指定的约束是不严格的。 换句话说,有一些场景可以通过基本类型对域服务方法进行参数化。

这两个约束如何促进不变性?

这个想法是,域服务不会改变状态,并且所有状态更改都通过参数显式地。 这是一个纯函数函数的本质。 如果域服务补充实体,那么它们的方法应该用这些术语来表达。

什么是功能样式?

我指的是功能程序。 函数式编程通常需要不变性和纯函数。 函数式方法的另一个特性是声明式风格( 与命令性对比) 。

因此我们应该尝试( 因为它可能不可能总是使用力) 强制服务将域对象用作参数并返回值

否,如果基本类型足以进行操作,则没有理由将它的强制为其他类型。 实体和价值对象的使用只是一个准则,有些人更喜欢更严格。 例如有些使用显式类型来表示每个实体的标识。 因此,你不必使用 int 来创建一个名为 OrderId的值对象来表示订单的标识。

因这里,由于域实体/值对象的某些内在特性,在大多数情况下它们的行为( 。IE 他们的操作) 是基本类型( 。IE 使用基元类型作为参数) 。

我不会说这是DDD的。 我指的是组合的更一般的概念- 复杂实体( 非 ddd ) 由简单的元素组成。 通过这个标记,复杂实体的操作将以组成部分表示出来。

更新2

域服务可以通过返回对象的新实例而不是修改传入的对象来避免状态突变。 这种方法的签名完全描述了它所做的事情,因为没有副作用。

一个域服务可以改变传递给它的对象的状态,在这种情况下,返回类型可能是完全的。 然而这是不太理想的- 它会更好地改变它自己的状态。

是的,那是它的一部分。 不变性和纯度允许你重构代码,这样就像将代数方程重置为代替代码一样。 另一个原因是,如果查看一段不可以变的数据,那么它就会更容易地推理代码。

d ) 是的,尽管在这种情况下,域对象会更好地变异自身。 这种变异将由周围的应用程序服务调用。 很多时候我将域服务传递给实体行为方法以提供它们不能直接访问的功能。

操作关闭的概念并不是它本身促进不变性,但是它是不可以变代码的一个特性。 原因是,如果域服务方法接受类型T的值,并返回类型T的值,则可以指出返回的新值。 这是一个不变性的特性,因为由操作产生的更改显式地作为一个新对象。

更新 3

这与传统OOP有更多的关系,而不是用 DDD 。 OOP试图隐藏对象后面的移动部件- 封装。 FP试图最小化移动部件- 不变性。 在某些情况下,可以将不变性视为更多的"自然"。 例如在事件中心场景中,事件是不可变的,因为它们是发生的事件的记录。 你不会更改发生的内容,但可以创建补偿操作。

b 再次,OOP OOP OOP information基于信息专家 Pattern essentially essentially essentially数据的行为应该尽可能接近于数据的that 。 这意味着实体应该尽可以能多地封装所包含的数据,以确保它的完整性。

原作者:
...