DI:组合物根分解

Pav*_*vel 6 dependencies dependency-injection inversion-of-control code-injection

组成根看起来很奇怪的模式.我们有一个非常大的上帝对象,它知道任何事情.

将组合根分解为某些模块的正确方法是什么,这些模块将封装对象图的自身部分的初始化?

什么层次的依赖注入

Mar*_*ann 9

我不同意组合根是上帝对象的前提.虽然从概念上讲,组合根可能包含许多代码行,但它只有一个责任:组成一个对象图.

组合根可以包含很多数据,并且它本身可以耦合到整个应用程序,但它在概念上只有一种方法.它只有一个改变的理由,那就是你想改变你的应用程序的组成方式.

此外,虽然组合根与应用程序的其余部分耦合,但应用程序代码不知道组合根.因此,根据依赖性倒置原则,耦合仅在一个方向上进行.

一种表达方式是上帝对象违反了所有五种SOLID原则,而组合根至少遵循SRP,ISP和DIP.我不认为OCPLSP适用于此.

总而言之,如果组合根组成一个大型应用程序,它仍然可以包含很多代码.如果您发现它变得无法管理,那么您应该如何将其分解为更小的代码块?

与分解任何其他代码的方式相同.它取决于它.

我希望我从来没有写过或说组合根只能是一个单一的类.如果我这样做,我想收回那个.在撰写作文集时,我经常将其职责分为多个班级(尽管很少超过一些).您可以应用任何您想要的设计模式或其他OOD技术来实现该目标.然后,Composition Root将成为您实现的Facade.

我不能提供更多的指导,因为它取决于应用程序架构.如果进行垂直切片,则很可能需要以不同于水平分层的方式构造组合根,等等.

也就是说,作为一般规则,我认为尝试将依赖图分解为子树并不有用.首先,因为依赖图是一个,而不是一棵树,还因为你经常需要交错多个独立的问题.你可以,例如,有子图,负责应用程序的各个子部分,但随后你需要交错相同的日志记录机制,或相同的缓存机制,或者相同的安全机制等全国整个图表.如果你试图将它们分开,你不能轻易做到这一点.


Mat*_*ans 1

组合根并不是真正的上帝对象,因为它只知道对象图的未封装部分。

在组件层次结构中,组合根具有一定数量的子级,它创建的对象图具体化了这些子级之间的相互依赖关系。交易门户可能配置有股票策略、共同基金策略和经纪商界面。这些策略需要经纪人界面,而门户 UI 需要一个或多个策略。组合根将它们连接在一起。

现在,任何这些注入的依赖项(交易策略或经纪商接口)都可以具有许多内部功能,这些功能也可以通过依赖项注入进行配置,但组合根不应具有有关这些内部结构的任何硬编码知识。相反,可以使用工厂实现来配置组合根以构建复杂的依赖关系。

工厂实现可能需要来自组合根的资源。例如,交易策略工厂都需要经纪人接口实现。但它们都需要组合根中相同的东西,因此组合根不需要了解它们的细节。

如有必要,传递到工厂的资源可以包括对组合根不透明的工厂的 DI 配置。因此,工厂可以创建任何适合实现它们应该创建的对象的对象图。

需要注意的是,工厂接口(应用程序调用它来构造所需的对象)是特定于应用程序。满足特定类型的依赖关系的所有可配置方式都是相同的。TradingStrategyFactory例如,上面会有一个接口,针对共同基金(使用共同基金模块)和股票(使用股票模块)有不同的实现。

除非工厂接口以某种方式标准化,否则工厂接口和实现是应用程序的一部分,而不是实现它们使用的功能的模块的一部分。

有时,需求会发生变化,某些新模块将需要组合根未提供的资源或连接。这将需要更改工厂接口及其所有实现。它不需要更改其他模块,因此这些工厂实现是应用程序本身的正确组成部分。

所以,最后......你的问题的答案是,一个庞大而复杂的组合根分解为各种不同的工厂实现。

您还提到了 Angular 中的分层 DI。这是一种自动将配置的资源传递到组件工厂的机制。我不熟悉 Angular,但我猜想这是必需的,因为 Angular 试图为所有组件标准化单个工厂接口。这会导致以难以理解的方式将对象图本身的构造移动到 DI 配置中。如果您在 .net 中编程,则不需要这个,并且我会在该环境中避免它。