Domain driven design 如何在DDD中对由其他实体组成的实体进行建模?

Domain driven design 如何在DDD中对由其他实体组成的实体进行建模?,domain-driven-design,Domain Driven Design,让我们创建一个由不同类型的多个设备(实体)组成的机器(实体)。我们在机器上有一个方法来启动它,该方法将调用组成机器的设备的初始化方法。我在如何建模方面遇到了问题。如果我从启动的角度来看,这显然是一台机器的行为,它属于机器实体。但实现需要委托给各种设备实体。我可能将机器建模为聚合根,并在其中包含一组设备。但是,对于每个设备所执行的行为,它们也可能是一个聚合根。至于到目前为止我发现的,我可以在启动方法中使用双重分派,并传入设备集合。在这种情况下,调用方负责提供此集合。但是既然机器实体知道设备是由什么

让我们创建一个由不同类型的多个设备(实体)组成的机器(实体)。我们在机器上有一个方法来启动它,该方法将调用组成机器的设备的初始化方法。我在如何建模方面遇到了问题。如果我从启动的角度来看,这显然是一台机器的行为,它属于机器实体。但实现需要委托给各种设备实体。我可能将机器建模为聚合根,并在其中包含一组设备。但是,对于每个设备所执行的行为,它们也可能是一个聚合根。至于到目前为止我发现的,我可以在启动方法中使用双重分派,并传入设备集合。在这种情况下,调用方负责提供此集合。但是既然机器实体知道设备是由什么组成的,为什么呢?将每个设备的回购协议注入机器显然是不好的。将启动方法委托给域服务也是一种选择,但这不是一种明确的机器实体行为吗?还有别的想法吗?如何根据DDD指南对此类案例进行最佳建模

class Machine
{
   DeviceKey[] Devices{ get;}

   void Startup()
   {
      foreach(var dvcKey in Devices)
      {
        //how to get the entity for the given dvcKey?
        //so we can call init on it? like
        dvc.Initialize();
      }     
   }
}
更多信息:首先,感谢您的回答和阅读。代码只是原型代码,因为问题是概念性的,如果我编写不变量、用例、事务分析等,它将成为一个与模式无关的巨大规范?当然,这个领域是复杂的,我们正在用各种设备对一台物理机器进行建模,每个设备将执行不同的逻辑,例如,一些逻辑,机器状态的验证是在所有设备上执行的(每个设备都是ar的候选设备?)。我们有几个用例,一个用户操作机器,比如启动、关闭,其他用户使用机器(使用会话等)。域中充满了实体,没有一个是哑的。您将如何处理此类合计

我在这里补充了更多的细节,尽管我觉得我们只能走一条路,吃我们做的东西。我们的第一次尝试是将machine作为聚合根,并将设备作为其一部分,如下所示:

class Machine
{
  Device1Type Device1{}
  Device2Type[] Devices2{}
  void Startup()
  {
    Device1.Initialize();
    foreach(var dvc in Devices2)
    {
      dvc.Initialize();
    }
    //etc...
  }
}

但这会导致并发性(一致性)问题,因为每个设备都会从机器的repo中获取以执行其行为。此外,各种设备的状态将通过根(机器)持久化,并且对于要执行其行为的设备,需要加载整个机器的状态-可能也会有性能问题。因此,我们将远离机器的设备建模为聚合。我们现在有问题了。如何从一个聚合(机器)访问并委托给其他聚合(设备),而不会泄漏到内存中?我想我们只需要为启动操作提供一个域服务,因为它可能是一个过程,而不仅仅是一个操作/方法。再次感谢您的阅读

就像@guillaume31在评论中所说的那样——如果不了解你的域名,就不可能真正回答这个问题。不过,我有一些可能有用的提示,可以为您指出正确的方向

使用域服务 当你觉得需要执行一些不适合你的聚合的操作时,你应该考虑使用域名服务——DDD构建块之一。我不能说这会解决你所有的问题-你最了解你的域名,所以你可以决定使用域名服务是否有用

做一些实际的建模! 如何根据DDD指南对此类案例进行最佳建模

class Machine
{
   DeviceKey[] Devices{ get;}

   void Startup()
   {
      foreach(var dvcKey in Devices)
      {
        //how to get the entity for the given dvcKey?
        //so we can call init on it? like
        dvc.Initialize();
      }     
   }
}
这个问题没有普遍的答案。细化代码中应该存在的聚合并在它们之间绘制责任边界不是一项简单的任务。您应该遵循无处不在的语言,注意聚合的内聚性,并真正考虑这些聚合应该保护的不变量。我要说的是,一次考虑所有这些事情并不是一个人的工作——整个开发团队都应该参与建模阶段

最强大和有趣的技术之一是事件风暴,由阿尔贝托·布兰多利尼发明。事件风暴可以让您快速探索困难的业务流程,还可以使用DDD进行建模—请参阅和。很少有事件风暴会议可以帮助您回答有关设计聚合的问题


这些提示可能无法直接回答您的问题,但我希望它们能起到有用的指导作用。

就像@guillaume31在评论中所说的那样-如果不了解您的领域,就不可能真正回答这个问题。不过,我有一些可能有用的提示,可以为您指出正确的方向

使用域服务 当你觉得需要执行一些不适合你的聚合的操作时,你应该考虑使用域名服务——DDD构建块之一。我不能说这会解决你所有的问题-你最了解你的域名,所以你可以决定使用域名服务是否有用

做一些实际的建模! 如何根据DDD指南对此类案例进行最佳建模

class Machine
{
   DeviceKey[] Devices{ get;}

   void Startup()
   {
      foreach(var dvcKey in Devices)
      {
        //how to get the entity for the given dvcKey?
        //so we can call init on it? like
        dvc.Initialize();
      }     
   }
}
这个问题没有普遍的答案。细化代码中应该存在的聚合并在它们之间绘制责任边界不是一项简单的任务。您应该遵循无处不在的语言,注意聚合的内聚性,并真正考虑这些聚合应该保护的不变量。我要说的是,一次考虑所有这些事情并不是一个人的工作——整个开发团队都应该参与建模阶段

最强大和有趣的技术之一是事件风暴,由阿尔贝托·布兰多利尼发明。事件风暴可以让您快速探索困难的业务流程,还可以使用DDD进行建模—请参阅和。很少有活动讨论会可以帮助您回答有关设计aggrega的问题