12

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

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

但是当您的应用程序中有大量类时会发生什么?说 1000+,你希望这些在容器中可用吗?

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

在分离方面,如何:

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

另一方面,我知道Symfony2 使用 XML/YAML进行 DiC 配置,但是当应用程序包含这么多类时,实际上这并没有过多地讨论事物的架构方面。

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

4

3 回答 3

10

假设您的所有类都将通过 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 - 容器隐藏,哪些类不隐藏。最好在最有利的地方使用 DI,也就是最有可能实现更改但调用者不知道接口已更改,调用者也不对此类更改感兴趣的地方。如果您以此为指导,那么您能否区分哪些类通过 DI - 容器隐藏,哪些类不隐藏。最好在最有利的地方使用 DI,也就是最有可能实现更改但调用者不知道接口已更改,调用者也不对此类更改感兴趣的地方。如果您以此为指导,那么您能否区分哪些类通过 DI - 容器隐藏,哪些类不隐藏。

于 2013-05-18T17:29:39.767 回答
7

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

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

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

此外,诸如视图和其他特定于功能的类和代码之类的东西可能不会由 DIC 管理。

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

于 2013-05-09T13:47:09.923 回答
6

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

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

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

对象需求应该只能从对象的构造函数或方法签名中读取,并通过依赖注入提供给该对象,通过您的代码库提供控制反转,帮助可测试性、可维护性和灵活性,并通过它提供大大简化的多态性。

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

在现实生活中,您不会通过将整个五金店(希望如此)运送到建筑工地来建造房屋,这样您就可以访问您需要的任何零件。相反,工头 ( __construct()) 询问将需要的特定零件 (DoorWindow) 并着手采购它们。您的对象应该以相同的方式运行;他们应该只询问完成工作所需的特定依赖项。提供对House整个硬件商店的访问权充其量是糟糕的 OOP 风格,最坏的情况是可维护性的噩梦。rdlowrey - auryn

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

总之,依赖注入容器永远不会变得“太大”,除非你做错了并将它们用作服务定位器或美化的对象关联数组!您不会为了在需要时将它们拉出而将所有物体推入其中。我不在乎它们是否延迟加载。使用实际的喷油器。甚至不要提及 Laravel 或“门面”。

于 2014-11-20T11:00:35.217 回答