实体的单一责任(改变的原因)应该是唯一地标识自己,换句话说,是可以发现其责任的。
埃里克·埃文(Eric Evan)的DDD书,第16页。93:
实体的最基本责任是建立连续性,使行为清晰可预测。如果他们备用,他们会做到最好。与其着重于属性甚至行为,不如将实体对象的定义简化为最固有的特征,尤其是那些识别该特征或通常用于查找或匹配该特征的特征。仅添加对于该行为所需的概念和属性必不可少的行为。
除此之外,还希望将行为和属性删除到与核心Entity相关联的其他对象中。除了身份问题外,实体还倾向于通过协调其拥有的对象的操作来履行其职责。
1。
...将ENTITY对象的定义简化为最固有的特征,尤其是那些识别它或通常用于查找或匹配它的特征。仅添加对该概念必不可少的行为...
为实体分配一个唯一的ID后,它的身份就会建立,因此我认为这样的实体不需要任何行为就能维持其身份或帮助其识别自己。因此,我不明白作者用“ 对于概念必不可少的行为 ” 指的是什么行为(除了find
和match
操作之外)?
2。
...将ENTITY对象的定义简化为最固有的特征,尤其是那些识别它或通常用于查找或匹配它的特征。...除此之外,还希望将行为和属性删除到与核心ENTITY相关的其他对象中。
因此,任何无助于识别实体的行为,但我们仍将其表征为该实体的固有特征(即吠叫是狗固有的,飞行是飞机固有的,产卵是鸟类固有的.. ),应该放入与该实体关联的其他对象中(例如:我们应该将吠叫行为放入与dog实体关联的对象中)?
3。
除此之外,还希望将行为和属性删除到与核心ENTITY相关联的其他对象中。
一)MyEntity
代表的职责A_resp
和B_resp
对象a
,并b
分别。
即使大多数的A_resp
和B_resp
工作是由做a
和b
的情况下,客户端仍担任A_resp
并B_resp
通过MyEntity
,这意味着,从客户的角度来看,这两个职责属于MyEntity
。这样,难道这不是意味着MyEntity
也有A_resp
和B_resp
责任,因此违反了SRP?
b)即使我们假设A_resp
并且B_resp
不属于MyEntity
,MyEntity
仍然有责任AB_resp
协调对象a
和的操作b
。因此,不MyEntity
违反SRP,因为它至少具有两项职责 –唯一标识自己,以及AB_resp
?
class MyEntity
{
private A a = ...
private B b = ...
public A GetA()
{ ... }
public B GetB()
{ ... }
/* coordinates operations of objects a and b */
public int AworkB()
{ ... }
}
/* A encapsulates a single responsibility resp_A*/
/* A is value object */
class A
{ ... }
/* B encapsulates a single responsibility resp_B*/
/* B is value object */
class B
{ ... }
更新:
1。
在这种情况下,行为是指语义行为。例如,用于唯一标识它的类的属性(即域对象的属性)具有行为。虽然这不能直接在代码中表示。预期的行为是该属性将没有任何重复的值。
因此,在代码中,我们几乎永远不需要真正实现某种方式(即操作)以某种方式保持实体的身份,因为正如您所解释的,这种行为仅作为概念存在于域模型中(以ID属性的形式存在)。实体),但是当我们将此ID属性转换为代码时,其语义的一部分会丢失(即,隐含地确保ID值唯一的那一部分)?
2。
此外,诸如Age之类的属性在Person实体之外没有上下文,因此移入其他对象没有任何意义。但是,信息可以很容易地存储在唯一标识符所在的单独位置,因此对行为的混淆。年龄可能是延迟加载的值。
a)如果Age
属性是延迟加载的,那么即使在语义Age
上仅仅是属性,我们也可以将其称为行为。
3。
您可以轻松进行特定于地址的操作,例如验证其是否为有效地址。您可能在设计时不知道这一点,但是整个概念是将对象分解为最小的部分
虽然我同意通过移动Age
到其他对象来丢失上下文DateOfBirth
,但是如果将属性移动到另一个对象中,上下文也不会丢失,但是通常不会移动它。
我们Address
移入另一个对象而不是移入另一个对象的主要原因是DateOfBirth
什么?因为DateOfBirth
是Person
实体固有的,或者是因为将来在某处发生的可能性较小,所以我们可能需要定义特定于DateOfBirth
?的操作。
4.我必须说,我仍然不知道是否MyEntity
也有A_resp
和B_resp
责任,为什么MyEntity
也已经AB_resp
不被认为是违反了SRP
EULERFX
1)
作者所指的行为是与实体相关联的行为。这些是修改实体状态的行为
a)如果我理解正确的话,你说,实体应该只包含那些行为,修改其属性(即其状态)?
B)又是怎么回事的行为不一定修改实体的状态,但仍被认为是一种内在该特性的实体(例如:吠叫是固有的一个特征Dog
的实体,即使它没有修改狗的状态)?我们应该将这些行为包含在实体中还是应该将其转移到其他对象?
2)
至于将行为转移到其他对象上,作者专门指的是价值对象。
尽管我的报价未包括在内,但作者确实在同一段落中提到,在某些情况下,行为(和属性)也将转移到其他实体中(尽管我了解将行为转移到VO 的好处)
3)假设MyEntity
(见问题3.在我原来的职位)不违反SRP,我们会说一个责任的MyEntity
是除其他事项外还组成:
一个。A_resp
+ B_resp
+ AB_resp
(AB_resp
协调对象a
和b
)
要么
b。 AB_resp
+委托A_resp
和关联B_resp
到的对象(a
和b
)MyEntity
?
4)埃里克·埃文(Eric Evan)的DDD书,第16页。94:
CustomerID是Customer ENTITY的唯一标识符(图5.5),但是电话号码和地址通常用于查找或匹配Customer。这个名字并没有定义一个人的身份,但是经常被用作确定身份的一部分。
在此示例中,电话和地址属性移入“客户”,但是在一个实际项目中,该选择将取决于通常如何匹配或区分域的客户。例如,如果客户有许多用于不同目的的联系电话号码,则该电话号码与身份无关,应与销售联系人保持联系。
一个)
CustomerID是Customer ENTITY的唯一标识符(图5.5),但是电话号码和地址通常用于查找或匹配Customer。这个名字并没有定义一个人的身份,但是经常被用作确定身份的一部分。
Quote指出只有与身份相关的属性才应保留在实体中。我假设笔者意味着实体应该只包含那些属性是经常被用来查找或匹配该实体,而其他所有的属性应该被移到?
b)但是其他属性应该如何/在何处移动?例如(假设这里不使用address属性来查找或匹配 Customer
,因此我们想将address属性移出Customer
):
如果不是创建Customer.Address
类型string
的属性,而是将地址属性移到关联的VO对象(类型),而不是创建Customer.Address
类型Address
的属性Address
,Customer
还是说仍然包含地址属性?
C)
在此示例中,电话和地址属性移入“客户”,但是在一个实际项目中,该选择将取决于通常如何匹配或区分域的客户。例如,如果客户有许多用于不同目的的联系电话号码,则该电话号码与身份无关,应与销售联系人保持联系。
这里的作者不是错的,因为如果我们假设许多仅属于该特定联系人的联系电话号码中的每一个,那么我想说这些电话号码与身份的关联就像只有一个电话号码时一样?Customer
Customer
Customer
5)
作者建议剥离实体的原因是,当一个实体最初创建一个Customer实体时,有一种趋向于将其认为可以与客户关联的任何属性填充到该实体中。这是一种以数据为中心的方法,它忽略了最终导致贫血领域模型的行为。
题外话,但我认为贫血的域模型从运动成绩行为出的实体,而你的例子是填充的实体有很多属性,这将导致Customer
有太多的行为(因为我们很可能还包括在Customer
该行为其修改这些其他属性),从而违反SRP?
谢谢