依赖注入:在什么时候可以创建一个新对象?


13

我正在重构PHP应用程序,并且我试图做的是尽可能多的依赖项注入(DI)。

我觉得我已经很好地了解了它的工作原理,而且我当然可以看到我的课程变得更加精简和强大。

我进行重构,以便可以在类中注入依赖关系而不是创建一个新对象,但是在某些时候,我将不得不创建一些对象,即使用dreaded new关键字。

我现在遇到的问题是我实际上可以在什么时候创建新对象?看起来我将结束于顶级课程,创建大量新对象,因为没有其他可去之处。这感觉不对。

我读过一些使用工厂类创建所有对象的博客,然后将工厂注入其他类中。然后,您可以调用工厂方法,然后工厂为您创建新对象。

我担心的是,现在我的工厂班将new全部免费!我猜这是工厂类的方法,这可能是可以的,但是使用工厂模式和DI时是否要遵守一些规则,还是我在这里偏离了常规?



我建议使用IoC来提供服务和策略。对于模型或助手类,我只使用new。当然,有一些入口点需要调用IoC容器,但不应太多。通常,您只需配置一次IoC,然后根据每个请求要求解决一个类。对于MVC,通常是控制器。
CodesInChaos

您提到的顶级类是“合成根”的一部分。这没有错。
Facio Ratio

Answers:


12

经过大量搜索之后,似乎(如上面的评论中所提到的)我正在谈论的顶级类称为Composition Root

在此组合根中添加所有对象的创建(或从此处引用IoC容器)似乎确实是公认的解决方案。

我最初的担心是,这个顶级班级最终会变得一团糟。在某种程度上是正确的,但是利弊权衡。例如,我可以看到我所有其他类的可读性,可测试性和可维护性都得到了改善。

顶层类可能有点凌乱,散落着newset_property(),但我不得不说,其实我更喜欢有所有这些代码在一个地方,而不是散落各地的其他类

另一个有用的页面在这里讨论此方法的性能影响


1
+1是因为我之前从未听说过“合成根”。
c_maker 2013年

2

工厂类将new遍及整个工厂。它将创建您要请求的任何对象,并可能创建该对象的依赖项。由于工厂的工作是为您new在此类中实例化正确的对象不是一件坏事。

DI使您可以进行松耦合设计。您可以通过更改提供给每个对象的依赖性来对应用程序进行更改。使您的应用程序灵活,可扩展且易于测试。

在顶层,您将具有实例化几个工厂,建立与服务的连接并发送响应的代码。它将有大量的new或静态调用来实例化应用程序所需的对象。那就是那个地方。


-2

我的两分钱在这里:

我正在重构一个php应用程序,我正在尝试进行尽可能多的依赖注入

您没有说明是否使用依赖项注入框架。我认为你绝对应该。使用可以为您提供所需功能的工具:https : //stackoverflow.com/questions/9348376/guice-like-dependency-injection-frameworks-in-php

我现在遇到的问题是我实际上可以在什么时候创建新对象?看起来我将结束于顶级课程,创建新对象的负载,因为没有其他可去之处。这感觉不对。

通常,您使用配置或中心点来实例化组成您的应用程序的初始对象。容器将为您创建对象。

然后,您可以通过IoC容器访问对象(服务,提供者,控制器...)。如果需要,它将为您透明地创建一个对象,或者为您提供对适当的现有实例的引用。

当然,在对象的特定实现中,您可以实例化不需要DI的其他对象(数据结构,自定义类型等),但这是正常的编程。

我读过一些使用工厂类创建所有对象的博客,然后将工厂注入其他类中。然后,您可以调用工厂方法,然后工厂为您创建新对象。

通常,如果希望IoC框架通过工厂实例化某些IoC对象,则可以使用Factory(在实例化特定对象时需要做一些额外的工作)。如果可以使用“ new Object()”简单地创建对象并设置一些属性,则不必使用Factory模式。

换句话说,我会说对一个或一组类使用Factory模式取决于您要对这些类建模的方式,而不取决于您是否使用DI(除非您的DI实现明确要求工厂,这是不寻常的)。

您还可以将IoC框架配置为在使用已经需要使用Factory的3rd party库时使用Factory。在这种情况下,您对此无能为力,并且需要告诉您的IoC容器:“嘿,当我请求这些接口之一时,必须使用该工厂为我提供适当的实例”。

我担心这样做,因为现在我的工厂班级将成为新的免费课程!我想这可能是可以的,因为它们是工厂类,但是在使用工厂模式和DI时有一些规则要遵守,否则我将偏离正常范围。

在这种情况下,听起来您不需要为这些对象/服务/控制器/任何对象使用Factory模式,并且只需配置IoC即可使用“新”实例化适当的类并注入其他所有内容。

希望对您有所帮助。


感谢您的回答,但是IoC容器肯定是我所指的“顶级类”。如果我只能在那里创建对象,那将是一团糟。
Gaz_Edge

4
doing DI manually beats the whole purpose of using an Inversion of Control container-如果您的意思是“ ...正在将依赖关系集中在配置文件中”,那么您是对的,因为这就是IoC容器真正所做的全部。DI的真正目标是去耦,您可以通过在构造函数方法中提供依赖项来实现。您根本不需要DI框架即可做到这一点。
罗伯特·哈维

嗯,您不创建对象,而是向IoC容器(在您需要的任何地方)请求它们,或者使用字段/参数注入,以便您的类自动注入适当的类,这些类始终由IoC容器创建。
jjmontes

1
我同意您需要一个用于大型应用程序的框架。许多应用程序没有那么大,并且无法从使用DI框架的额外复杂性中受益。
罗伯特·哈维

2
我不是那样说的。我只是说过,您不需要DI容器即可。
罗伯特·哈维,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.