|
|
1
218
这种差异似乎很小,但即使使用ServiceLocator,该类仍然负责创建其依赖项。它只是使用服务定位器来实现。有了DI,类就有了依赖关系。它既不知道,也不关心它们来自哪里。这样做的一个重要结果是,DI示例更容易进行单元测试——因为您可以通过它的依赖对象的模拟实现。您可以将两者结合起来——如果需要,可以注入服务定位器(或工厂)。 |
|
|
2
109
当您使用服务定位器时,每个类都将依赖于您的服务定位器。依赖注入的情况并非如此。依赖项注入器通常在启动时只被调用一次,以将依赖项注入某些主类。这个主类所依赖的类将递归地注入它们的依赖项,直到你有一个完整的对象图。 一个很好的比较: http://martinfowler.com/articles/injection.html 如果依赖项注入器看起来像服务定位器,类直接调用注入器,那么它可能不是依赖项注入器,而是服务定位器。 |
|
|
3
56
服务定位器隐藏依赖关系——例如,当对象从定位器获得连接时,通过查看对象无法判断它是否访问了数据库。通过依赖项注入(至少是构造函数注入),依赖项是显式的。 此外,服务定位器打破了封装,因为它们提供了对其他对象的依赖关系的全局访问点。使用服务定位器, as with any singleton :
使用依赖项注入,一旦指定了对象的依赖项,它们就在对象本身的控制之下。 |
|
|
4
47
马丁·福勒州 :
简而言之:服务定位器和依赖注入只是依赖倒置原则的实现。 重要的原则是依赖抽象,而不是具体。这将使您的软件设计松散耦合、可扩展、灵活。 你可以用最适合你需要的。对于一个拥有庞大代码库的大型应用程序,您最好使用服务定位器,因为依赖注入将需要对代码库进行更多更改。 你可以查看以下帖子: Dependency Inversion: Service Locator or Dependency Injection 也是经典: Inversion of Control Containers and the Dependency Injection pattern by Martin Fowler Designing Reusable Classes 拉尔夫·E·约翰逊;布莱恩·富特 然而,让我大开眼界的是: ASP.NET MVC: Resolve or Inject? Thatâs the Issue⦠by Dino Esposito |
|
|
5
27
使用构造函数DI的类向使用代码的用户指示存在需要满足的依赖项。如果类在内部使用SL来检索此类依赖项,则使用代码的代码不知道这些依赖项。表面上看,这似乎更好,但实际上了解任何显式依赖关系都是有帮助的。从建筑的角度来看更好。在进行测试时,您必须知道一个类是否需要某些依赖项,并配置SL以提供这些依赖项的适当假版本。有了DI,只要把假货传过来就行了。差别不大,但确实存在。 不过,DI和SL可以一起工作。为常见的依赖项(如设置、记录器等)设置一个中心位置非常有用。给定一个使用此类DEP的类,可以创建一个接收DEP的“实”构造函数,以及一个从SL检索并转发给“实”构造函数的默认(无参数)构造函数。 编辑:当然,当你使用SL时,你会给这个组件引入一些耦合。这很讽刺,因为这种功能的想法是鼓励抽象和减少耦合。这些顾虑是可以平衡的,这取决于需要使用SL的地方有多少。如果按照上述建议进行,只需在默认类构造函数中进行。 |
|
6
17
它们都是IoC的实现技术。还有其他实现控制反转的模式:
服务定位器和DI容器似乎更相似,它们都使用容器来定义依赖关系,从而将抽象映射到具体实现。 主要区别在于依赖项的位置,在服务定位器中,客户端代码请求依赖项,在DI容器中,我们使用容器创建所有对象,并将依赖项作为构造函数参数(或属性)注入。 |
|
|
7
8
在我的上一个项目中,我使用了这两种方法。 我使用依赖注入来实现单元的可测试性。我使用服务定位器来隐藏实现,并依赖于我的IoC容器。是的!一旦你使用了一个IoC容器(Unity、Ninject、Windsor Castle),你就依赖它了。一旦它过时了,或者出于某种原因您想交换它,您将/可能需要更改您的实现——至少是组合根。但服务定位器将这一阶段抽象化。 你怎么能不依赖你的IoC容器呢?要么你需要自己包装它(这是个坏主意),要么你使用服务定位器来配置你的IoC容器。因此,您将告诉服务定位器获取所需的接口,它将调用配置为检索该接口的IoC容器。 就我而言,我使用 ServiceLocator ,这是一个框架组件。我用 Unity 我的IoC容器。如果将来我需要交换我的IoC容器 Ninject ,我只需要将我的服务定位器配置为使用Ninject而不是Unity。容易迁移。 这里有一篇很好的文章解释了这种情况; http://www.johandekoning.nl/index.php/2013/03/03/dont-wrap-your-ioc-container/ |
|
8
7
添加的一个原因是受上周我们为MEF项目编写的文档更新的启发(我帮助构建MEF)。
一旦一个应用程序可能由数千个组件组成,就很难确定是否可以正确实例化任何特定组件。通过“正确实例化”,我的意思是在这个例子中基于
在您给出的第二个示例中,构造函数转到IoC容器以检索其依赖项,这是您可以测试IoC实例的唯一方法
这在测试时会产生各种尴尬的副作用,因为在运行时工作的代码不一定在测试工具下工作。mock不会这样做,因为真正的配置是我们需要测试的,而不是一些测试时设置。 这个问题的根源是@Jon已经指出的区别:通过构造函数注入依赖项是声明性的,而第二个版本使用命令式服务定位器模式。
如果小心使用,IoC容器可以静态地分析应用程序的运行时配置,而不会实际创建所涉及组件的任何实例。许多流行的容器提供了一些变化;
微软作文
,这是MEF目标的版本。NET4.5Web和Metro风格的应用程序,提供
(见 this example ). 通过验证 成分根 在测试时对应用程序进行测试,您可能会发现一些错误,否则这些错误可能会在稍后的测试过程中漏掉。 希望这是一个有趣的补充,在这个问题上,否则全面的答案集! |
|
|
9
6
我认为这两种方法是协同工作的。 依赖注入意味着将一些依赖类/接口推送到一个消费类(通常是它的构造函数)。这通过一个接口将两个类解耦,这意味着消费类可以使用多种类型的“注入依赖”实现。 服务定位器的作用是整合您的实现。您可以在程序开始时通过一些引导设置服务定位器。引导是将一种实现类型与特定抽象/接口相关联的过程。在运行时为您创建。(根据您的配置或引导)。如果没有实现依赖注入,使用服务定位器或IOC容器将非常困难。 |
|
10
5
以下简单的概念让我更清楚地理解了服务定位器和DI容器之间的区别:
然而,我们只能在具体的消费者使用情况下讨论这两者之间的区别。在composition root中使用服务定位器和DI容器时,它们几乎是相似的。 |
|
11
5
注意:我并没有完全回答这个问题。但我觉得这对依赖注入模式的新学习者很有用,因为他们对它和 Service Locator (anti-)pattern 碰巧无意中发现了这一页。 我知道服务定位器(现在似乎被认为是一种反模式)和依赖注入模式之间的区别,并且可以理解每个模式的具体示例,但是我被在构造函数中显示服务定位器的示例搞糊涂了(假设我们正在做构造函数注入)。 “服务定位器”通常既用作模式的名称,也用作引用该模式中使用的对象(假设也是)的名称,以便在不使用新操作符的情况下获取对象。现在,同样类型的对象也可以在 composition root 执行依赖注入,这就是困惑所在。 需要注意的是,您可能正在DI构造函数中使用服务定位器对象,但您没有使用“服务定位器模式”。如果将其称为IoC容器对象,那么就不那么令人困惑了,因为您可能已经猜到它们基本上做了相同的事情(如果我错了,请纠正我)。 无论它被称为服务定位器(或仅仅是定位器),还是IoC容器(或仅仅是容器),正如您所猜测的,都没有区别,它们可能指的是同一个抽象(如果我错了,请纠正我)。只是,将其称为服务定位器表明,我们正在使用服务定位器反模式和依赖注入模式。 IMHO将其命名为“locator”,而不是“location”或“locting”,有时也会让人认为文章中的服务定位器指的是服务定位器容器,而不是服务定位器(反)模式,尤其是当有一个称为依赖注入而非依赖注入的相关模式时。 |
|
|
12
4
在这种过于简化的情况下,两者没有区别,可以互换使用。 然而,现实世界的问题并不是那么简单。假设Bar类本身有另一个名为D的依赖项。在这种情况下,您的服务定位器将无法解析该依赖项,您必须在D类中实例化它;因为实例化它们的依赖关系是类的责任。如果D类本身有其他依赖项,情况会变得更糟,而在现实世界中,它通常会变得更加复杂。在这种情况下,DI是比ServiceLocator更好的解决方案。 |
|
|
13
4
服务定位器和依赖注入都是 对象访问模式 遵守 依赖倒置原理 依赖注入是[静态/全局]对象访问模式 服务定位器是[动态]对象访问模式 如果你需要处理[ 动态结构 ]就像[ 用户界面树 ]或者你需要的任何应用程序。 例子:
如果你只想从你的类中得到一个实例 不关心应用程序的层次结构 和 实例在该层次结构中的位置 ,你应该使用DI。 例子:
服务定位器在您不知道时使用 真正的提供者 在运行时之前对服务进行更新。 当你知道它是 提供 那项服务。 服务定位器模式更像是一个 模块级 依赖提供者,而DI是 全球层面 . 当有一个 子模块 声明应该由其 父模块 而不是静态解析类型(singleton/transient/static scoped)。 它可以通过 范围注射模式 范围由应用程序的模块结构/关系定义。 个人建议:
|
|
|
14
1
依赖注入和服务定位器之间有什么区别(如果有的话)?这两种模式都擅长实现依赖倒置原则。服务定位器模式更容易在现有的代码库中使用,因为它使总体设计更加松散,而不必强制更改公共接口。出于同样的原因,与基于依赖注入的等效代码相比,基于服务定位器模式的代码可读性较差。 依赖项注入模式很清楚,因为类(或方法)将具有哪些依赖项的签名。因此,生成的代码更干净,可读性更强。 |
|
|
15
0
DI容器是一个 超集 服务定位器。它可以用来 定位服务 ,具有额外的 组装(连接)依赖注入 . |
|
|
16
-3
记录在案
除非您真的需要一个接口(该接口由多个类使用),否则不能使用它 .在这种情况下,IBar允许利用实现它的任何服务类。然而,通常情况下,该接口将由单个类使用。 为什么使用界面是个坏主意?。因为调试非常困难。 例如,假设实例“bar”失败,问题: 哪门课不及格?。 我应该修改哪个代码? 一个简单的视图,它通向一个界面,这就是我的路的尽头。 相反,如果代码使用硬依赖项,则很容易调试错误。
如果“bar”失败,那么我应该检查并关闭BarService类。 |