Domain driven design DDD:我应该对域实体采取什么样的行为?

Domain driven design DDD:我应该对域实体采取什么样的行为?,domain-driven-design,entity,solid-principles,Domain Driven Design,Entity,Solid Principles,我的团队非常努力地坚持将领域驱动设计作为一种架构策略。但是,大多数时候,我们的领域实体相当贫乏。我们希望在我们的域实体上增加更多的业务/域行为 例如,活动记录将数据访问放在实体上。我们不希望这样,因为我们乐于使用存储库模式进行数据访问 此外,我们将软件设计为坚固的(Bob叔叔将五个软件设计原则放在一起)。因此,在设计实体时,关注单一责任、开闭、liskov、接口分离和依赖倒置对我们来说很重要 那么,我们应该包括哪些行为?我们应该远离哪种类型?我试图将某些行为放入我的域、实体或值对象中 持久化之前

我的团队非常努力地坚持将领域驱动设计作为一种架构策略。但是,大多数时候,我们的领域实体相当贫乏。我们希望在我们的域实体上增加更多的业务/域行为

例如,活动记录将数据访问放在实体上。我们不希望这样,因为我们乐于使用存储库模式进行数据访问

此外,我们将软件设计为坚固的(Bob叔叔将五个软件设计原则放在一起)。因此,在设计实体时,关注单一责任、开闭、liskov、接口分离和依赖倒置对我们来说很重要


那么,我们应该包括哪些行为?我们应该远离哪种类型?

我试图将某些行为放入我的域、实体或值对象中

持久化之前的验证。 转换到新状态之前的验证。例如,订单聚合根实体可以在进入发送状态之前验证其内部状态及其聚合子级。 最小化获取集属性并尽可能多地使用值对象。首先,它通过行为使模型更加丰富。实体更具描述性。第二,如果必须对接受Adress值对象作为in参数的person实体使用值对象方法(如ApplyAddress方法),则很少将实体置于无效状态

还有。。。
信息情报。使用实体及其值对象控制和限制聚合信息。像人格一样,人格可以是一个处理人的独特性的价值对象。它包含ssn、ssn算法、处理ssn上的性别校验和等。

实体的行为应反映业务模式。可以对该实体执行或由该实体执行的操作是业务世界应该是可以对实体类执行或由实体类执行的操作。例如:

在在线购物系统中,您可以将产品添加到购物车中。因此,Cart类应该如下所示:

public class Cart
{
    //...

    public void AddProduct(Product product)
    {
        ...code to add product to cart.
    }
}
//newEmployeeService comes from somewhere else... possibly injected using IOC
newEmployeeService.Create(newEmployee, someManagerId);

有人可能会说methid应该反映用例。

如果您必须询问应该对域实体采取什么行为,那么您可能不需要DDD。我试图在这里提供帮助,因为我在尝试将DDD安装到一个不属于它的地方时经历了很多痛苦

DDD甚至是在发现域复杂度太高,任何其他模式都无法工作后可以遵循的模式。因此,仅CRUD不适用于DDD。根据我的理解,DDD适用于包含复杂业务规则的有界上下文,这些规则需要在转换聚合根的状态之前运行。所以我不会在复杂的定义中包含验证

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


希望这能有所帮助。

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

域应该(在代码中)表示业务是什么或做什么(在现实生活中)。因此,域实体是在现实业务中发现的工件或参与者。那些现实生活中的人工制品和演员有什么样的行为?所有这些。反过来,域实体应该有什么样的行为?所有这些

例如,在现实生活中,经理可以雇佣新员工。域的表示应该包括“经理”和“新员工”等实体。这里的经理是演员

//newEmployee comes from somewhere else... possibly the UI
//someManagerId comes from the logged in user
var manager = _repository.Get<Manager>(someManagerId);
manager.Hire(newEmployee);
在一个贫血的域中,您可以使用这样的域服务来创建或雇用员工。它是有效的,但它没有表现力,行为也不那么容易被发现。谁做什么?为什么要求经理创建新员工


我想当我最初问这个问题时,我想尝试在我的实体中包含更多的行为,但如果不将服务注入实体(例如,使用构造函数注入),我真的不知道该怎么做。从那时起,我们学会了一些新技巧,我们团队的实体表现力非常强。简而言之,我们正在做的是:

  • 在可能的情况下,我们尝试使用参与者实体来表达执行动作的人或事物
  • 参与者有表达他们可以执行的动作的方法
  • 当需要一个服务时,它会作为参数注入到使用它的方法中
  • 我们在每个域实体上的每个方法上触发域事件,以提供可扩展性并使实体具有自持久性

  • 单一责任与领域驱动设计截然相反。几个月前,我们在纽约市城市发展和发展委员会的会议上对此进行了一次有趣的讨论……我对那个讨论很感兴趣。我认为情况并非如此,如果想就ddd和行为进行更深入的讨论,请给我发电子邮件。新员工呢。它是由工厂创建的还是由存储库创建的?它会通过创建引发域事件吗?域事件应该由存储库处理,还是应该超出域层?我可能问得太多了:DIm也在试图这样做。Like call=营销者。call(客户);询价=营销商。进行询价(客户,日期);我很好奇你是如何在ORM和数据库设计中配置你的经理的。管理器是否在单个表继承中?我正在进行单表继承,但我不需要鉴别器列。基本上,参与者只具有不同角色的相同数据。+1表示您的观点#3(当需要服务时,它作为参数注入到使用它的方法中)。我看到很多人(包括我自己)都无法理解这一微妙之处。当你思考它时,以这种方式组织它是有意义的,而不是