如何在不同的有界上下文中将学说实体拆分为更多的域实体?

时间:2017-02-14 03:39:54

标签: php doctrine-orm domain-driven-design

我正在尝试DDD(Domain-driven design)字段中的第一步。我喜欢明智的规则,你应该将你的实体分成许多较小的,特定于上下文的实体(例如User实体几乎在每个非ddd或设计不佳的应用程序中都会过度生长。但是如何在php中使用Doctrine(有效)做到这一点有什么共同的选择?

我们说我有两个有界的背景:StoreInvoicing

每个都有两个域实体: 对于商店BC FirstTimeCustomerRecurrentCustomer 对于发票BC VatCustomerNonVatCustomer

现在,在我的基础架构层中,我希望它们都保存在同一个(至少是基础)表中,以便能够通用UserId(Uuid)引用它们。对我来说问题是,如何做到这一点,所以我可以利用我的存储库实现中的doctrine自动化。

我读到了可能是解决方案的单表继承或Class Table Inheritance,但是:

我需要能够使用同一个Uuid的User,因为它在每个上下文中都是不同的类型。

我需要能够在商店BC的AbstractStoreCustomer上返回一些FirstTimeCustomer又名RecurrentCustomer$storeCustomerRepository->find(1);

并在发票BC中的AbstractInvoicingCustomer上返回VatCustomer又名NonVatCustomer$invoicingCustomerRepository->find(1);

但似乎我被迫在这里选择BC我想要的实体的特定身份。因此,对我来说,在DDD背景下没有任何意义。

我还阅读了Mapped Superclasses,看起来也是选项,但是:

  

这意味着在映射上无法实现一对多关联   超类。

我需要Customer与订单有关系,这两个实体应该可用(也可能不希望它可用于新BC中的某种新型User实体)。

我得出结论,我应该怀疑我错过了什么,是吗?我应该如何将上帝实体打造成更小的特定背景?

1 个答案:

答案 0 :(得分:7)

我将从一些一般规则开始。 在考虑DDD时,您必须拒绝任何关于持久性的想法(表和主键等)。您必须设计聚合根和实体,就像将它们存储在文件中一样。当你设计模型时,如果想到关于表或ORM的想法你就不能做DDD;退一步重新开始。

正如我所看到的,你通过有限的上下文分割你的模型开始了。如果你没有通过BC拆分它们,你最终会想到包含所有行为的巨大模型,然后持久性会影响性能,因为在DDD中,聚合会持久存储在一个事务中。另一件事,尽量避免继承并使用组合。

话虽如此,让我们谈谈你的业务。 在Authentication BC中,有Users可以通过一些凭据进行身份验证。在公元前Store,有Customers买东西。在Invoice BC,还有Customers,但也有不同的模型(如果需要,可以使用不同的类)。在公元前Shipping,还有Customers,但又是一个不同的模型。这些Customer模型共享BC中的一些属性,例如nameid。因此,您使用id来识别现实生活中的某个人,但是根据上下文使用不同的模型来封装他们的行为。

我认为你不应该有AbstractStoreCustomer,你应该只有Customer并试图找出它们在抽象类/接口中的区别,例如BuyingHistoryProfile和2实现{{ 1}}和FirstTimeCustomer。此类应仅包含有关购买配置文件的行为,并且应由RecurrentCustomer BC中的每个Customer引用。同样地,尝试在Store BC中提取一个类来进行价格计算。

现在我们已经创建了模型,我们可以考虑持久性。对于每个有界上下文,创建一个Invoicing表,其中包含共享属性(Customername)以及id BC的特定属性(buyingHistoryProfileStore BC等priceCalculationStrategy

如果您想知道存在一定程度的数据重复,那么您是对的,但这是正常的,有必要将模型分离。当Invoicing BC中的User更改其名称时,将同步此重复数据:您将更新所有其他模型。从这个角度来看,AuthenticationInvoice BC是下游流,它们使用来自Store BC的数据;在启动更新时,这取决于您的业务。

作为事件驱动架构的粉丝,我建议您看看CQRS(甚至是事件采购)。我认为这些架构非常适合这个应用程序。根据我的经验,CQRS可以让你的模型清洁10倍。通过事件采购,您很可能甚至不必使用Authentication。您可以在阅读方面使用ORM,如果您真的喜欢它们,或者无法离开它们。我个人不喜欢(并且不要使用)ORM