DDD 处理执行相同操作的 2 个域

DDD dealing with 2 domains performing same actions

不太确定如何解决有关 DDD 的这个问题。

假设您有 2 个域:

A Product 可以不属于 Store 而存在。 Store 可以在没有任何 Products 的情况下存在(我知道这没有意义,但这只是我正在使用 atm 的复杂解决方案的一个简单示例。)

因此,当 Person 进入系统时,它们可以从任一端开始。他们可以从创建新的 Products 开始,也可以从添加新的 Store 开始。

这就是事情变得复杂的地方,当他们创建一个新的 Store 时,他们可以选择添加现有的 Products 或者他们可以创建一个新的 Product 并添加它到 Store.

你如何处理这个用例。 Store 是否对 CreateNewProduct 有行为,它负责设置新的 Product,然后将其添加到 Store。或者您只是在 Store 域之外创建一个新的 Product 作为 Product 域的一部分,然后告诉 StoreAddProduct / AddExistingProduct

更新: 这样的东西是否适合 Domain Service

public class StoreProductService {

    public Store CreateNewStoreProduct (Store store, string sku, string name, etc){

        Product newProduct = ProductFactory.CreateNewProduct(sku, name, etc);

        store.AddProduct(newProduct);

        return store;
    }
}

这个业务问题很常见。您肯定可以找到一些有关使用 DDD 的电子商务系统的示例。

典型的情况是您还没有完成 UL 的开发。如果您与您的领域专家讨论商店(我不会将其标记为代码,因为我在谈论 UL 术语,而不是 类),您会发现商店只关心产品可用性,而不关心产品本身.

通常,属于产品目录的产品与可用性关系不大。它可能有一般描述、制造商详细信息、原产国、图片、包装尺寸和重量等。

然而,Product Availability 具有可用性,即可用产品项目的数量。它可能有一些额外的细节,例如保留物品的数量、预计到达的物品等。

事实是,尽管这两个概念相当不同,但通常这两个概念都被领域专家称为 "Product"。这是两个独立限界上下文的典型示例。

一旦在两个不同的限界上下文(和物理位置)中有两个不同的东西被称为 Product,您就需要使它们保持同步。这通常是通过在限界上下文之外发布域事件并通过在那里订阅这些事件并在限界上下文中执行内部域命令处理来更新另一端来完成的。

您需要两个域相互通信。您可以使用各种方法进行通信,但一种常见的方法是使用 REST API。在您的 Store 域中,您需要能够与 API 通信或知道如何通信的东西。我通常将这些实现为包装 api 调用的服务。该服务将能够理解您的域通用语言并将其翻译成 API 命令。您可以使用领域事件来监听产品何时创建,然后您可以将商店与产品相关联,或者您可以实施某种轮询机制。

请求示例,所以这里是:

Call from UI (probably from a controller)

StoreService.CreateStore(storeName: String, newProduct : StoreProduct) You could pass in primitives to represent the newproduct. This allows you to create a new product without the need for a new class for it. You subsequently don't need a shared infrastructure class or converter between your domain and UI layers.

StoreService

public StoreService
{
      public StoreService(ProductApiClient productApiClient...)...
      public void CreateStore(string StoreName, StoreProduct prod...)
      {
             var newStore = StoreFactory.Create(storeName);
             //below might be better as an asynch call but for simplicity
             //keeping it all synchronous
             var newProd = productApiClient.CreateProduct(prod);
             //check if product was created successfully, if so
             newStore.Add(newProd);
             //save
             StoreRepo.Create(newStore);
             //check if store was created successfully
       }

这里的要点:

  1. 使用工厂创建您的聚合实体(在此状态下它尚未持久化)。
  2. 您需要一个存储库来序列化您的新存储并将其持久保存到您的数据存储中。
  3. 产品Api客户端将在您的域模型和对产品的请求之间进行转换Api。它知道如何在给定域实体的情况下生成 Api 请求(例如 REST)。
  4. 产品Api客户端将从Api响应中return一个域实体。
  5. 您使用商店实体将新产品添加到商店。
  6. 您使用存储库保存您的商店
  7. 如果 api 的调用很耗时,您可以选择更异步的方法。

此示例说明了 DDD 和关注点分离的强大功能。根据项目的大小和要求,这可能过于乏味,因此适合您的需要、技能和要求。