有界的上下文实现和设计

时间:2014-02-06 07:03:04

标签: domain-driven-design repository-pattern aggregateroot onion-architecture bounded-contexts

假设我有两个有界的上下文, Shipping Context Billing Context 。这些背景中的每一个都需要了解客户。

在数据级别,客户由数据库中的CustomerTbl表表示。该表包含描述客户的所有必要列。

CustomerTbl中的列(简化):

  • Name
  • PhysicalAddress
  • PaymentMethod

运费背景NamePhysicalAddress有关,而结算背景Name和{{1>有关}}

送货背景中,我已对汇总PaymentMethod进行了建模:

  • Recipient现在拥有RecipientName
  • 的属性/值对象

结算背景中,我已对汇总PhysicalAddress进行了建模:

  • Payer包含PayerName
  • 的属性/值对象

PaymentMethodRecipient聚合都由上下文边界完全分隔。他们也有自己的存储库。

问题:

  1. 使用相同的“数据库表”,是否可以使用多个聚合(假设它们位于不同的有界上下文中)?

  2. 在更多有限的背景下可能需要客户数据。这不意味着每个有界上下文的许多聚合,存储库和工厂实现吗?代码中会有一定程度的冗余。这不会影响可维护性吗?

  3. 在聚合中拥有共享属性是否可以接受?一个例子是客户Payer属性。这也意味着冗余的验证码?

2 个答案:

答案 0 :(得分:9)

Q&安培; A

  

1)使用相同的“数据库表”来拥有多个聚合(假设它们位于不同的有界上下文中)是否可以接受?

  • 只要您遵循严格的管理共享状态的策略,我就可以接受。
  • DDD是可以接受的,因为域被认为比数据更重要。
  • 只要完成工作而不引入(太多)隐藏成本,您的客户就可以接受。
  

2)在更多有限的背景下可能需要客户数据。这不意味着每个有界上下文的许多聚合,存储库和工厂实现吗?代码中会有一定程度的冗余。这不会影响可维护性吗?

不一定,请查看shared kernel pattern

  

3)在聚合中拥有共享属性是否可以接受?一个例子是客户名称属性。这也意味着冗余验证码?

与问题1相同的答案。关于冗余,一旦拥有共享内核,您可以简单地将验证器类放在那里。

关于您在DRY和DDD之间的冲突:

优雅的代码并没有不必要地使伟大的设计原则相互矛盾。通常有一种方法可以满足这些原则。你还没有找到它,因为要么你不理解这些原则,要么你没有足够地解剖你的问题。

(如果这听起来很教条,那是因为软件工程实际上是一种宗教信仰)

答案 1 :(得分:4)

<强>数目:

1.是否聚合及其存储库是只读的。如果单独更改模式或数据而不通知其他模式或数据,则在有界上下文之间共享存储和模式可能是一个问题,但我认为在这种情况下这不是一个大问题。

但如果收据和付款人可编辑,这是一个不同的故事。有可能人们可以修改它们,这会在有限的上下文中产生影响。例如,客户可能需要更改特定装运单的地址,但共享cutomer表可能会更改客户装运订单的所有地址,恕不另行通知。所以最好为它们使用不同的存储空间。

2.不同的有界背景需要客户的不同方面。我认为仅依赖于必要的数据是一种很好的做法,因此聚合抽象可能会有所不同。潜在的可维护性问题可能在实现方面发生(主要是因为重复代码)。因此,我们可能会引入一个额外的组件来返回客户的所有方面,并在其上构建有界的上下文特定适配器。