我将创建一个“WarehouseShelf”域对象,用例从存储库中检索该域对象。然后用例可以将 WarehouseBoxUnit 放入货架。如果规则不适用,WarehouseShelf 可以拒绝。如果 WarehouseShelf 接受 WarehouseBoxUnit,您可以将 WarehouseShelf 传递给存储库的持久化方法。
当存储库创建 WarehouseShelf 时。您不得加载所有 WarehouseShelfBoxUnit 来创建 WarehouseShell。也许创建一个 WharehouseBoxUnitDescribtion 就足够了,它可以判断它是否与您要添加的盒子的盒子描述兼容。
WarehouseShelf 也可以有一个 WarehouseConditions 对象,可以判断它是否有工作空调。 WarehouseBoxUnit 可以告诉它需要的存储条件,您可以询问 WarehouseConditions 是否满足这些条件。
所以最后我的域模型看起来像这样:
+---------+ +--------------------+
| BoxUnit | ----> | BoxUnitDescription |
+---------+ +--------------------+
+--------------+ * +------------+ 0..1 +--------------------+
| Shelf | -----> | ShelfSpace | -------> | BoxUnitDescription |
+--------------+ +------------+ +--------------------+
| add(BoxUnit) |
+--------------+
|
|
V
+---------------------+
| WarehouseConditions |
+---------------------+
Shelf 可能有一个单独的列表来存储添加的 BoxUnit,可能是 ShelfModifications,因为 ShelfSpace 只知道 BoxUnitDescriptions。
或者您可以在 ShelfSpace 中使用 BoxUnit 而不是 BoxUnitDescription。
在任何一种情况下,实体都与对外部数据的访问分离,当您想要对规则进行单元测试时,您可以简单地创建一个带有 BoxDescriptions、WarehouseConditions 的 Shelf 并向其添加一个 BoxUnit。
编辑
另一种方法是使用域名服务Voughn Vernon 将其描述为:
域中的服务是完成特定于域的任务的无状态操作。通常,您应该在域模型中创建服务的最佳指示是当您需要执行的操作感觉不适合作为聚合或值对象上的方法时。为了减轻这种不舒服的感觉,我们的自然倾向可能是在聚合根的类上创建一个静态方法。但是,在使用 DDD 时,该策略是一种代码味道,可能表明您需要一个服务。
Voughn Vernon,Implementing Domain-Driven Design,第 7 章服务
但请注意,使用域服务通常会导致 anemic domain model,我认为您应该避免。这就是为什么我没有在我的答案的第一个版本中提到它。但这可能是适合您情况的解决方案。