1

我正在实现有界上下文之间的交互,我发现它“以某种方式”削弱了开放封闭原则,我不确定这是设计 BC 和要考虑的常见权衡的自然结果还是我的设计失败。

考虑 Shop BC,您可以在其中使用一些商品从购物车中创建订单。创建的订单由OrderItems 组成,它们中的每一个都包含各种类型的ItemSpecification值对象接口中的一种,例如ProductSpecificationor FooServiceSpecification,保护不变量并包含一些数据。创建 Order 时,会发出任何其他 BC 可以侦听的异步事件。

该异步事件是从 Order 中创建的,并表示为(序列化的)OrderCreatedEvent 对象,包含 OrderDTO 对象,全部放置在与每个 BC 共享的 Core 命名空间中,因此任何 BC 都可以依赖 Core,但不能依赖其他方式。到目前为止一切都很好,几乎:

该 OrderItemDTO 必须包含 interface ItemSpecificationDTO,需要为每种类型的规范实现。我的ItemSpecificationVO(与任何其他 VO/Entity in Order 一样)具有toCoreDTO()实用地实现简单翻译的方法,并且它也使得实现新的相对困难ItemSpecification并且忘记根据 DTO 实现。那应该没问题。

但是听那个事件的其他 BC 呢?在每个 BC 中,该事件需要在其反腐败层中进行转换,并且 BC 可能只对某些类型感兴趣ItemSpecificationDTO并将它们转换为各种值对象,这对于特定的 BC 很重要。

正如鲍勃叔叔所说的关于 OCP 的机智:

您应该能够扩展系统的行为而无需修改该系统。

但是当我实现新类型时ItemSpecification,对于每个可能对这种新类型感兴趣的 BC,我需要专门从 CoreDTO 翻译那个新类型(好吧,我可以编写一些抽象来在每个 BC 中进行翻译,所以我仍然只是添加代码而不修改任何东西,比如添加 if($x instanceof X))。但是,通过添加新类型,ItemSpecification我需要在其他 BC 中进行适当的扩展(甚至可能修改某些内容,因为我们并不生活在理想世界中)。

我不知道该怎么想。这是整个 DDD 方法的缺点吗?或者也许确实是功能,因为在其他 BC 中寻找需要进一步扩展的内容、地点和方式是由领域需求而不是技术问题驱动的?似乎是对的。最后,我正在尝试进行领域驱动设计:-) 但在我看来这也有点危险。恐怕有一天我们会忘记更新其他 BC 并发生一些不好的事情。但这可能是因为我也扮演着领域专家的角色,“恐惧”应该属于这个角色。我的问题只是坐在两把椅子上还是我做错了什么?:-)

4

1 回答 1

1

关于这个主题有很多有趣的细节,但我将在这里集中讨论有界上下文的一个特定方面。

那就是他们有界是有原因的。就像在这些上下文的模型/理解之间应该有一个界限。两个上下文,即使它们是相关的,也应该对系统有不同的看法,即使对可能部分共享的数据也是如此。

在我看来,您的“有界上下文”希望在同一个模型上工作。您甚至创建了每个人都可以看到并且显然必须能够理解的“核心”模型。如果是这种情况,我认为您失去了拥有不同上下文的好处,而您只是在使用一种模型创建一个大型应用程序。

为了纠正这个问题,我认为您需要摆脱任何中心/核心模型,并在不同的上下文/服务中使用“本地”(有界)模型。当您需要与其他组件通信时,您需要为这两个组件定义一个协议,由一方或双方指定。

例如,购物车可能需要知道后端系统的产品 ID 才能在那里创建订单。但是后端系统不需要知道购物车使用的模型来了解订单的内容(在它自己的模型中)。

于 2017-05-12T08:46:47.330 回答