什么时候依赖注入容器会变得太大,我该怎么办呢?

时间:2013-05-09 12:32:02

标签: php oop dependency-injection

我们都知道为什么依赖注入很棒,因为它使代码更少耦合,更容易测试,并且更好阅读!然后有些人决定使用像pimple这样的依赖注入容器来帮助PHP在Dependency Inversion中协助SOLID原则。

因此,当使用pimple创建DiC,将其传递给控制器​​,并在闭包中创建所有新对象时,实际上只有在开发人员调用$container['object']时才会实例化,这很棒!

但是当你的应用程序中有一个非常大的类时会发生什么?说1000+,你想在容器中提供这些吗?

开发方面,这将是一场噩梦,将这些全部放在一个文件中。将它们分开的最佳方法是什么,或者另一种建议是否更可取?

在分离方面,如何:

  • 创建容器
  • 根据应用程序包含多个类别组合在一起的文件
  • 以递增方式添加到容器,直到文件末尾包含

另一方面,我知道Symfony2 uses XML/YAML用于DiC配置,但是当应用程序包含这么多类时,实际上并没有谈论架构方面的内容。

开发人员拥有如此庞大的代码库时可以做些什么?

3 个答案:

答案 0 :(得分:9)

假设您的所有课程都将通过DI容器调用。

首先是一个小小的比较案例: 如果你去商店购买一条裤子,那么你几分钟就在使用DI。例如,您不必告诉您需要的尺寸,帮助您获得专业知识的人员。你将不得不说你想要什么类型的裤子,商店的人会根据你的意愿给你一些裤子(或者让你知道这是不可能的)。一个不是DI的例子是所有这些裤子来自的问题的答案。对于进入商店的顾客来说,这个问题的答案完全无关紧要。它永远不会成为进入商店的理由,那里需要一条特定类型的裤子。 您可以询问某种类型的未指定问题,您将得到确切的答案。这是DI的核心。如何完成不是您的业务,也不是您的关注。但你什么都不能问。例如,您不能在布料商店购买面包。问题必须与特定的DI主题(界面)相关。

Pimple是一个关联数组。它不是DI容器。据你所知,DI容器会返回一个接口,DI容器知道要加载哪个实现。让我举个例子来告诉你Pimple不是DI容器的地方。 你在商店,你选择了一条裤子,你想买它。现在你要付钱了。怎么样?再次是DI。对你来说没问题,你有几种可用的交易方法,你会选择一种方法。系统如何回答对你来说并不感兴趣:你什么都不说,只需拿到你的钱包并开始付钱。

在Pimple中,您必须选择要用于付款的对象。客户将不得不说'我需要付款对象'。在一个真正的DI容器中你只需要以合法的方式交换钱(接口行为),并根据输入数据,DI容器知道选择哪种实现(现金,信用卡,主卡)。你不必担心。如果您仍然需要担心,为什么称它为依赖注入? Pimple是他最好的服务定位器,但要使用DI,你将不得不使用一个接口。否则没有什么可隐藏的,没有依赖注入。 : - )

所以,不要将Pimple用于DI。它不是DI容器。如果您打算使用Pimple(它可以很好地组织您的课程),那么就不要将其称为DI。它最好是一个服务定位器,但它并没有隐藏使用接口的实现。因此它不能是DI。

尝试整理代码库。不同类的功能是什么?哪些课程需要DI?我建议你只对执行功能需求的类使用DI。当您回到商店的案例时:商店人员直接与客户沟通的所有功能。不是为了实现如何走到后端试图找到另一条裤子。不适用于如何打开或关闭商店的过程。但是对于如何欢迎客户并询问某人想要拥有什么类型的裤子是的。 在您的应用程序中:是否存在直接与应用程序的访问者交互的接口/类,您是否可以创建某种类型的合同来描述交互?这就是DI容器的设计。 我不会在整个地方使用DI。 DI带来了性能损失和维护问题。您使用的DI越多,您拥有的层数越多,您知道在哪里发生的事情就越少。在最有利的地方使用DI,并且最有可能的是实现将改变,但是调用者不会知道接口已经改变,调用者也不会对这种改变感兴趣。如果你把它作为指导,那么你可以区分哪些类通过DI容器隐藏,哪些类没有。

答案 1 :(得分:7)

嗯,在考虑回答这个问题时,有几点需要考虑。但是主要的(我认为应该回答你的观点):

您真的使用所有1000个类作为依赖项吗?

通常,我们有大型应用程序,但它作为依赖项使用的典型部分实际上通常要小得多。原因是大量的类往往是域对象。在应用程序中表示数据或业务案例的对象。这些类几乎从不是依赖,而是使用工厂,映射器等创建的。

此外,DIC可能无法管理视图和其他功能特定的类和代码。

因此,您将拥有大部分不需要由容器管理的代码。

答案 2 :(得分:5)

我现在想自己回答这个问题。

依赖关系注入容器包含应用程序中的每个对象。它们被标记为容器的事实是这里的主要问题。 " DIC' S"像Symfony的Pimple 不是依赖注入者。它们是用于保存对象的美化关联数组,主要提倡Service Locator反模式。

在代码中查看$this->get('something'),就像在Symfony中一样?这是一个服务定位器。使用它,您正在隐藏类依赖项并使您的对象API变得模糊。这包括你的控制器!

对象要求应该可以从对象 的构造函数或方法签名中读取,并且通过Dependency Injection通过代码库提供Inversion of Control提供给此对象有助于测试性,可维护性和灵活性,通过它可以大大简化多态性。

依赖注入容器应该重命名为 injectors ,因为这是他们应该做的 - 为您注入依赖项。当你需要时,你不应该把物体拉出来。如果只是在需要时使用服务定位器将它们拉出来,你将如何使用DI和控制反转?

  

在现实生活中,你不会通过运输整个五金店(希望)来建造房屋   施工现场,以便您可以访问您需要的任何部件。相反,领班(__construct())   要求提供所需的具体部分(DoorWindow)并继续采购。   你的对象应该以相同的方式运作;他们应该只询问具体的依赖关系   要做好自己的工作。赋予House访问整个硬件商店的能力最差   OOP风格,最糟糕的是可维护性的噩梦。 rdlowrey - auryn

您可以使用反射来读取对象需求,然后自动实例化并注入依赖项。 Auryn是一个很棒的注入器。您可以在引导程序和控制器解析程序中进行设置,然后根据整个代码库中的对象类型提示编写SOLID代码以进行自动注入。任何抽象类/接口?没问题,你alias直接在代码中或通过从配置文件(最好)中读取它们并将它们以循环方式对它们进行混淆。使用配置文件意味着您可以随意使用基于配置的多态 - 仅通过创建新对象并在配置文件中更改一个字符串就可以将一个具体实现切换到另一个具体实现,这非常棒。

总之,依赖注入容器永远不会变得太大"除非你做错了并将它们用作服务定位器或一个美化的关联对象数组!你不要把所有物品都推到那里,以便在需要时将它们拉出来。我不在乎他们是否懒惰。使用实际注入器。并且甚至不提Laravel或外墙"。