【问题标题】:What are the technical reasons to avoid injecting the service container instead of individual services?避免注入服务容器而不是单个服务的技术原因是什么?
【发布时间】:2012-02-12 14:47:09
【问题描述】:

通常,当我需要将一个或多个服务注入另一个服务时,我会显式地注入每个服务。但是,我有一种情况,注入服务容器本身会让事情变得更容易。我知道这不是推荐的做法,但我很好奇阻止这种做法的技术原因是什么。它是合理的,比如它太耗费资源,还是更个人的感觉它太乱了?

【问题讨论】:

    标签: php symfony dependency-injection


    【解决方案1】:

    如果你注入容器,你并没有明确依赖关系。事实上,你比以前更模糊了它们。如果你有这样的课程...

    class DocumentCreator(IFileNamer fileNamer, IRepository repository)
    { ... }
    

    ...您可以看到依赖项是什么。您还可以轻松地模拟这些依赖项以进行单元测试,以确保隔离 DocumentCreator,并且可以知道任何测试失败都是其代码的结果,而不是其依赖项之一中的代码。

    另一方面,如果你这样做......

    class DocumentCreator(IDependencyContainer container)
    { ... }
    

    ...您已经掩盖了依赖关系。如果不检查该类的内部结构,您无法知道它需要一个 IFileNamer 和一个 IRepository。

    您也不能轻易知道需要在容器中放入哪些模拟来测试 DocumentCreator。模拟 IDependencyContainer 根本不会帮助你;你的类仍然会在测试中失败,因为容器不包含 IFileNamer 和 IRepository,除非你检查类的内部以查看它们是必需的。

    【讨论】:

      【解决方案2】:

      你描述的是一个ServiceLocator。这在现代应用程序设计中被认为是一种反模式。 This article 描述了原因。

      【讨论】:

      • 错误。人们真的需要停止链接到那个家伙的博客。这是来自更熟练的模式大师的见解。 martinfowler.com/articles/injection.html
      • @Colin 你读过 Mark Seemann 声明 ServiceLocator 为反模式的理由吗?您只获得了完全依赖注入的一些优点,但却错过了很多好处(即依赖关系的即时可见性)。我补充说 SL 违反了软件设计的各种规则,如封装blog.ploeh.dk/2015/10/26/service-locator-violates-encapsulation 或 SOLID blog.ploeh.dk/2014/05/15/service-locator-violates-solid
      • @Colin 您是否曾经遇到过类为您提供无参数构造函数然后拒绝工作的情况,因为您必须在一些看似无关的代码中初始化六个“内部细节”?不?幸运的你。如果我每小时都得到额外的报酬,我不得不浪费时间来定位和处理这些“内部细节”,我可以花半年时间去度假。 Trace 类有一个静态的监听器集合。这是一个明显的依赖关系,而不是“内部细节”。
      • 你没有抓住重点。调用trace的时候,是不是每次都传入构造函数中的监听器? DI 容器属性注入侦听器吗?通常不会,事实上,侦听器通常通过...基于文本的配置文件 (gasp) 进行初始化!相比之下,纯粹的 DI 方法可能会通过构造函数传入复合记录器类,并且在大多数情况下,这将是一种更麻烦、更不灵活的方法。同样,我并不是说 DI 永远不是正确的选择,我只是说,有时,像服务定位器或提供者这样的替代品可能是合适的。
      • @Colin,你说得对,隐藏类的内部细节很重要。问题在于,通过注入服务容器,您隐藏了类的external 细节。与方法和属性一样,类的依赖项也是公共 API 的一部分。如果您需要提供 X 和 Y 以使类运行,那么如果该类没有明确要求 X 和 Y(例如通过构造函数),您怎么知道? “当类在运行时爆炸时”不是这个问题的好答案。
      【解决方案3】:

      我认为这种方法的主要问题是您不再清楚地看到依赖关系。另一个问题可能是它更难测试。

      【讨论】:

      • 我绝对同意第一部分,这就是为什么除了极少数情况我仍然继续注入特定服务的原因。但我不确定测试会变得更加困难吗?
      • 这意味着创建容器对象,并将模拟(或非模拟)服务注入其中,而不是直接注入它们,这又迈出了一步。
      • 嗯,这绝对是一大劣势。
      猜你喜欢
      • 1970-01-01
      • 2016-07-26
      • 2017-12-04
      • 2023-03-20
      • 2021-08-11
      • 2013-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多