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

Jim*_*mbo 11 php oop dependency-injection

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

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

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

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

在分离方面,如何:

  • 创建容器
  • 根据应用程序将包含类的几个文件组合在一起
  • 逐步添加到容器,直到文件末尾包括

另一方面,我知道Symfony2使用XML/YAML进行DiC配置,但实际上当应用程序包含这么多类时,这并不是很多关于架构方面的讨论.

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

Loe*_*man 10

假设您的所有类都将通过DI容器调用.

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

疙瘩是一个关联数组.它不是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容器隐藏,哪些类没有.


irc*_*ell 7

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

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

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

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

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


Jim*_*mbo 6

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

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

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

对象要求应该从一个对象的构造或方法签名可读只,并提供一个通过该对象依赖注入提供反转控制通过您的代码库帮助可测试性,可维护性和灵活性大大简化多态性通过它被提供.

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

在现实生活中,您不会通过将整个五金店(希望)运送到施工现场来建造房屋,以便您可以访问所需的任何部件.相反,工头(__construct())询问需要(Door和Window)的具体部分并采购它们.你的对象应该以相同的方式运作; 他们应该只询问完成工作所需的具体依赖性.给House访问整个五金店充其量是可怜的OOP风格,在最坏的情况可维护性噩梦.rdlowrey - auryn

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

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