假设我有两个有界的上下文, Shipping Context 和 Billing Context 。这些背景中的每一个都需要了解客户。
在数据级别,客户由数据库中的CustomerTbl
表表示。该表包含描述客户的所有必要列。
CustomerTbl
中的列(简化):
Name
PhysicalAddress
PaymentMethod
运费背景与Name
和PhysicalAddress
有关,而结算背景与Name
和{{1>有关}}
在送货背景中,我已对汇总PaymentMethod
进行了建模:
Recipient
现在拥有Recipient
和Name
在结算背景中,我已对汇总PhysicalAddress
进行了建模:
Payer
包含Payer
和Name
PaymentMethod
和Recipient
聚合都由上下文边界完全分隔。他们也有自己的存储库。
使用相同的“数据库表”,是否可以使用多个聚合(假设它们位于不同的有界上下文中)?
在更多有限的背景下可能需要客户数据。这不意味着每个有界上下文的许多聚合,存储库和工厂实现吗?代码中会有一定程度的冗余。这不会影响可维护性吗?
在聚合中拥有共享属性是否可以接受?一个例子是客户Payer
属性。这也意味着冗余的验证码?
答案 0 :(得分:9)
1)使用相同的“数据库表”来拥有多个聚合(假设它们位于不同的有界上下文中)是否可以接受?
2)在更多有限的背景下可能需要客户数据。这不意味着每个有界上下文的许多聚合,存储库和工厂实现吗?代码中会有一定程度的冗余。这不会影响可维护性吗?
不一定,请查看shared kernel pattern。
3)在聚合中拥有共享属性是否可以接受?一个例子是客户名称属性。这也意味着冗余验证码?
与问题1相同的答案。关于冗余,一旦拥有共享内核,您可以简单地将验证器类放在那里。
优雅的代码并没有不必要地使伟大的设计原则相互矛盾。通常有一种方法可以满足这些原则。你还没有找到它,因为要么你不理解这些原则,要么你没有足够地解剖你的问题。
(如果这听起来很教条,那是因为软件工程实际上是一种宗教信仰)
答案 1 :(得分:4)
<强>数目:强>
1.是否聚合及其存储库是只读的。如果单独更改模式或数据而不通知其他模式或数据,则在有界上下文之间共享存储和模式可能是一个问题,但我认为在这种情况下这不是一个大问题。
但如果收据和付款人可编辑,这是一个不同的故事。有可能人们可以修改它们,这会在有限的上下文中产生影响。例如,客户可能需要更改特定装运单的地址,但共享cutomer表可能会更改客户装运订单的所有地址,恕不另行通知。所以最好为它们使用不同的存储空间。
2.不同的有界背景需要客户的不同方面。我认为仅依赖于必要的数据是一种很好的做法,因此聚合抽象可能会有所不同。潜在的可维护性问题可能在实现方面发生(主要是因为重复代码)。因此,我们可能会引入一个额外的组件来返回客户的所有方面,并在其上构建有界的上下文特定适配器。