2011-10-16 38 views
14

我的团队非常努力地坚持域驱动设计作为架构策略。但是,在大多数情况下,我们的域名实体非常有趣。我们希望在我们的域名实体上投放更多业务/域名行为。DDD:我应该将哪些行为放在域实体上?

例如,Active Record将数据访问放在实体上。我们不希望这样做,因为我们很乐意使用存储库模式进行数据访问。此外,我们将软件设计为SOLID(Bob的叔叔放在一起的五个软件设计原则)。因此,在设计我们的实体时,我们注意单一职责,开放关闭,liskov,界面隔离和依赖倒置,这对我们很重要。

那么,我们应该包括什么样的行为?我们应该远离什么类型?

+0

单一职责与域驱动设计非常相似。我们在几个月前的NYCDDD聚会上对此进行了一次有趣的讨论...... – Domenic

+0

我对这个讨论感兴趣。如果您想更深入地讨论ddd和行为,我并不认为 –

回答

19

我问了这个问题已经快一年了,从那以后我和我的团队学到了很多东西。以下是我今天要回答这个问题的方法:

该域应代表(在代码中)业务是或现在(现实生活中)。那么,领域实体就是现实生活中发现的制品或行为者。那些生命之物和演员有什么样的行为?所有的。反过来,什么样的行为应该域名实体对他们有什么?所有的。

例如,在现实生活中,经理可以聘请新员工。该域的代表应包括像“经理”和“新员工”这样的实体。经理是这里的演员。

//newEmployee comes from somewhere else... possibly the UI 
//someManagerId comes from the logged in user 
var manager = _repository.Get<Manager>(someManagerId); 
manager.Hire(newEmployee); 

因此,经理实体模拟/反映现实生活中的行为,在这里。另一种方法是跳过经理实体作为一个演员,并把他推下去的角落这么繁重工作“域名服务”可以做所有的工作......这样的:

//newEmployeeService comes from somewhere else... possibly injected using IOC 
newEmployeeService.Create(newEmployee, someManagerId); 

在贫血域,您可以使用这样的域名服务来创建或雇用一名员工。它有效,但不具表现力,行为不可发现。谁做了什么?为什么经理需要创建一个新员工?


我认为,当我问的问题本来,我想尝试启动,包括在我的实体的更多行为,但我真的没有不注射服务到我的实体(例如知道怎么回事,用构造函数注入)。从那以后,我们学到了一些新的技巧,我们团队的实体超级表现力。简而言之,我们正在做的是:

  1. 我们试图在可能的情况下使用演员实体来表达正在执行动作的人或事物。
  2. 参与者具有表达他们可以执行的动作的方法
  3. 当需要服务时,它被作为参数注入到使用它的方法中。
  4. 我们使用BlingBag对每个域实体上的每个方法发起域事件,以提供可扩展性并为实体提供自持的能力。
+2

新员工呢?它是由工厂还是存储库创建的?它是否会通过创作引发域名事件?域名事件是否应该由存储库处理,还是应该放在域名之外?我可能会问太多:D – inf3rno

+0

我也试图做同样的事情。像call = marketer.call(client); inquiry = marketer.makeInquiry(client,date); 我很好奇你是如何在ORM中配置你的管理器和数据库的设计的。单表继承中的管理器?我正在做单表继承,但我不需要鉴别器列。 基本上演员只有不同的角色具有相同的数据。 –

+0

为你的观点#3 +1(当需要服务时,它被作为参数注入到使用它的方法中)。我已经看到很多人(包括我自己)的这种微妙之处。当你考虑它时,以这种方式组织它比使用构造函数注入更有意义,因为它明确了每个动作的依赖关系。 – MetaFight

0

我尝试将其放入我的域,实体或值对象中的一些行为。

持久性验证。 在转换到新状态之前进行验证。例如,订单聚合根实体可以在进入已发送状态之前验证其内部状态及其聚合子。 尽量减少获取设置属性和使用值对象。首先,它使模型更加富有行为。实体变得更具描述性。其次,如果您必须在采用Adress Value对象作为参数的Person实体上使用ApplyAdress方法等值对象方法,那么您更少会将实体置于无效状态。

更多... 信息情报。使用您的实体及其价值对象来控制和限制汇总信息。像个人身份可以成为处理个人独特性的价值对象。它包含ssn,ssn算法,处理ssn等上的性别校验和。

+0

是我的电子邮件地址。 –

0

您实体上的行为应反映业务模型。商业世界应该成为实体阶层或实体阶层可以做的事情。例如:

在网上购物系统中,您可以添加产品到您的购物车。所以购物车类应该看起来像这样:

public class Cart 
{ 
    //... 

    public void AddProduct(Product product) 
    { 
     ...code to add product to cart. 
    } 
} 

可以争辩说,方法应该反映用例。

+0

or it is产品#AddToCart(Cart)??? – pinkpanther

3

如果你不得不问一下你应该把什么行为放在域实体上,那么你可能不需要DDD。我试图在这里提供帮助,因为我尝试将DDD安置到它不属于的地方时遇到了很多痛苦。

DDD甚至domain model是可以遵循后,发现该域名的复杂性过高,任何其他模式的工作模式。所以只是CRUD不适用于DDD。根据我的理解,当您有一个包含复杂业务规则的有界上下文时,DDD适用于需要在转换聚合根状态之前运行的业务规则。所以我不会在复杂的定义中包含验证。

您希望放入实体的行为类型与您试图解决的业务问题密切相关。对持久性(存储库等)的关注应该在(事实上,持久性可能存在于工作流或事件存储中)之后。

希望这会有所帮助。

相关问题