【发布时间】:2017-05-18 01:50:00
【问题描述】:
让我们有一个由多个不同类型的设备(实体)组成的机器(实体)。我们在机器上有一个方法来启动它,该方法将调用构成机器的设备的 Initialize 方法。我在如何建模时遇到问题。如果我从启动的角度来看,它显然是机器的行为,它属于机器实体。但是实现需要委托给各种设备实体。我可能将机器建模为一个聚合根,并在那里有一组设备。但是每个设备也可能是它执行的行为的聚合根。至于到目前为止我发现的内容,我可以在启动方法中使用双重调度并传入设备集合。在这种情况下,调用者有责任提供这个集合。但是,既然机器实体确实知道设备是由什么组成的,为什么?将每个设备的 repo 注入机器显然是不行的。将启动方法委托给域服务也是一种选择,但这不是清楚机器的实体行为吗?还有什么想法吗?遵循 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?)。我们有几个用例,因为一个用户将操作机器,例如启动、关闭,其他用户将使用机器(使用会话等......)域充满了实体,没有一个是愚蠢的。您将如何处理此类聚合?
我在这里添加了更多细节,尽管我觉得我们必须走一条路,吃我们做的东西。我们的第一次尝试是将机器作为聚合根,设备是其中的一部分,如下所示:
class Machine
{
Device1Type Device1{}
Device2Type[] Devices2{}
void Startup()
{
Device1.Initialize();
foreach(var dvc in Devices2)
{
dvc.Initialize();
}
//etc...
}
}
但这会导致并发(一致性)问题,因为每个设备都将从机器的存储库中获取以执行其行为。此外,各种设备的状态与根(机器)保持一致,并且为了使设备执行其行为,需要加载整个机器的状态 - 也可能存在性能问题。因此,我们将远离机器的设备建模为聚合体。我们现在从问题中得到了问题。如何从一个聚合(机器)访问和委托给其他聚合(设备)而不泄漏到贫血?我想我们只会为启动操作使用域服务,因为它可能是一个过程,而不仅仅是一个操作/方法。再次感谢您的阅读。
【问题讨论】:
-
如果没有关于领域的更多信息就无法回答:不变量、用例、事务分析等。就像现在一样,您的类只不过是愚蠢的容器,因此不建议使用 DDD。
-
好的,我想我们将尝试将 Startup 作为一种机器方法,将 DeviceProvider 作为参数传入(如方法注入),因为它是从应用程序服务调用的。 DeviceProvider 将提供设备并且 Startup 可以调用它的 Initialize。这样机器不处理设备(加载等),启动仍然是机器的方法。
-
我正在考虑在这里使用命令,并且处理程序是可以访问所有设备的处理程序。如果我们发现它毕竟是一个长时间运行的进程,我们可以稍后将处理程序中的实现重构为进程管理器。这样,我们也可以从域模型内部发出启动(重启)命令,而不仅仅是从应用程序中发出。服务?