【问题标题】:DDD dealing with 2 domains performing same actionsDDD 处理执行相同操作的 2 个域
【发布时间】:2016-03-07 21:46:56
【问题描述】:

不太清楚如何解决这个关于 DDD 的问题。

假设您有 2 个域:

  • Product 域负责创建新的和管理一个人创建的现有ProductsProduct Aggregate Root
  • 一个Store 域,负责将所有创建的Products 分配给给定的Store 以进行销售,以及其他内容。但是Store 也可以创建新的Products,这些Products 将分配给自己,但也可用于其他Stores,以便他们可以将Product 分配给自己。 Store Aggregate Root

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

所以当Person 出现在系统中时,它们可以从任一端开始。他们可以从创建新的Products 开始,也可以从添加新的Store 开始。

这里是复杂的地方,当他们创建一个新的Store 时,他们可以选择添加现有的Products,或者他们可以创建一个新的Product 并将其添加到Store

您如何处理这个用例。是Store 是否对CreateNewProduct 有行为,它负责设置新的Product,然后将其添加到Store。还是您只是在Store 域之外创建一个新的Product 作为Product 域的一部分,然后将Store 告诉AddProduct / 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;
    }
}

【问题讨论】:

  • 您需要第三个域,它应该充当门面模式。所以第三个域的工作是创建商店或产品或将它们关联在一起。门面模式将通过提供更简单的接口来访问产品和商店域,帮助您隐藏系统的复杂性,
  • 我和 adeel 在一起;您需要第三个概念 - ProductFactory 或类似的。产品不会自己创造,商店也不会创造产品——它们只是包含它们。
  • 是的,我有一个ProductFactory,它为我创建了一个新产品。但是你是否让StoreAddProduct(product) 或 CreateNewProduct(sku, name, etc). Which means that the Store` 实体需要知道ProductFactory。所以很明显,您将拥有一个Store 应用程序服务来处理添加新产品。那么在该创建方法中,您是否使用ProductFactory 并在创建后将其传递给商店?
  • @StephenByrne - 见上面的评论
  • 您是否将“域”与“聚合”混淆了?

标签: domain-driven-design aggregateroot bounded-contexts


【解决方案1】:

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

请求了一个例子,所以这里是:

从 UI 调用(可能来自控制器)

StoreService.CreateStore(storeName: String, newProduct : StoreProduct) 您可以传入原语来表示新产品。这使您可以创建新产品而无需为其创建新类。您随后不需要在域和 UI 层之间共享基础架构类或转换器。

商店服务

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. productApiClient 将在您的域模型和对 productApi 的请求之间进行转换。它知道如何在给定域实体的情况下生成 Api 请求(例如,如果是 REST)。
  4. ProductApiClient 将从 Api 响应返回域实体。
  5. 您使用商店实体向商店添加新产品。
  6. 您使用 repo 持久化您的商店
  7. 如果对 api 的调用很耗时,您可以选择更异步的方法。

此示例说明了 DDD 的强大功能和关注点分离。根据您的项目规模和您的要求,这可能会过于繁琐,因此请根据您的需求、技能和要求进行调整。

【讨论】:

  • 有应用服务不是更好吗?例如,您有一个StoreService,它是一个应用程序服务,它知道ProductFactory。所以从你的UI层,你会调用StoreServiceCreateNewrProduct,然后这会调用ProductFactoryCreateProduct,结果将返回到商店添加新添加的产品。
  • 那么你是在合并两个域或让逻辑泄漏。除了产品域在其 API 中公开的内容之外,商店服务不应该知道任何关于产品的信息。您的 UI 层应该调用 CreateNewStore(如果与商店域交互)并将足够的信息传递给应用程序服务可以在需要时创建新产品的位置(使用产品域公开的 api)。请记住,您可能需要执行“检查可用性”之类的操作或其他一些特定于产品的操作。这就是为什么您需要充分隔离到您的商店域不必知道这些事情的地方。
  • 这是有道理的。你能用一个假想的例子来更新你的答案吗?
【解决方案2】:

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

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

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

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

事实上,尽管这两个概念有很大不同,但它们通常被领域专家称为“产品”。这是两个独立限界上下文的典型示例。

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

【讨论】:

  • 尝试寻找电子商务解决方案,但实际上找不到涉及商店的示例。看到这样的例子,将极大地帮助我。然而,即使这看起来像一个电子商务解决方案,但它不是,我已经用 product 和 store 替换了真实的域,因为它足够接近,并且与我们正在尝试做的事情具有相同的逻辑。我不能给出一个实际的例子,因为它受 IP 保护
  • 这里的问题是每个设计都非常特定于实际领域。如果不了解您的领域并构建 UL 和 BC,几乎不可能给出具体的设计建议。本质上,正如 Vernon 所说,DDD 是“在有界上下文中开发无处不在的语言”。在你的情况下,因为这都是秘密的,所以你只能靠你自己,恐怕......带有上下文映射的电子商务示例可以在 IDDD 书中找到。
猜你喜欢
  • 1970-01-01
  • 2016-03-19
  • 1970-01-01
  • 1970-01-01
  • 2012-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-26
相关资源
最近更新 更多