这两种模式似乎都是控制反转原理的实现。也就是说,一个对象不应该知道如何构造它的依赖项。

依赖注入(DI)似乎使用构造函数或setter来“注入”它的依赖项。

使用构造函数注入的例子:

//Foo Needs an IBar
public class Foo
{
  private IBar bar;

  public Foo(IBar bar)
  {
    this.bar = bar;
  }

  //...
}

Service Locator似乎使用了一个“容器”,它连接了它的依赖项并给了foo它的bar。

使用Service Locator的例子:

//Foo Needs an IBar
public class Foo
{
  private IBar bar;

  public Foo()
  {
    this.bar = Container.Get<IBar>();
  }

  //...
}

因为我们的依赖关系只是对象本身,这些依赖关系有依赖关系,依赖关系有更多依赖关系,等等。因此,控制反转容器(或DI容器)诞生了。例如:Castle Windsor, Ninject, Structure Map, Spring等)

但是IOC/DI容器看起来完全像服务定位器。称它为DI容器是一个坏名字吗?IOC/DI容器只是另一种类型的服务定位器吗?当我们有很多依赖时,我们使用依赖注入容器,这是一个细微的差别吗?


当前回答

以下简单的概念让我更清楚地理解了Service Locator和DI Container的区别:

服务定位器用于消费者,它根据直接消费者的请求按ID从一些存储中提取服务 DI容器位于外部的某个地方,它从某个存储中获取服务并将它们推给消费者(无论是通过构造函数还是通过方法)

然而,我们只能在具体的消费者使用的背景下讨论它们之间的区别。当在组合根目录中使用Service Locator和DI Container时,它们几乎是相似的。

其他回答

服务定位器和依赖注入都是遵循依赖倒置原则的对象访问模式实现


依赖注入是[static/global]对象访问模式

服务定位器是[动态]对象访问模式


如果你需要处理[动态结构],如[ui树]或任何[分形设计的应用程序],你可能需要服务定位器。

例子:

React的createContext/useContext 提供/注入Vue angular的提供者

如果您只想从类中获取一个实例,而不关心应用程序的层次结构以及实例在该层次结构中的位置,那么您应该使用DI。

例子:

c# /Java中的注释


如果在运行时之前不知道服务的实际提供者,则使用Service Locator。

当您知道提供该服务的是静态容器时,就使用DI。


服务定位器模式更像是模块级别的依赖提供程序,而依赖注入模式是全局级别的。

当有一个子模块声明了一个服务的依赖关系,该服务应该由它的父模块提供,而不是静态解析类型(单例/瞬态/静态作用域)时,这是非常有用的。

它可以通过DI的作用域注入模式实现,而作用域则由应用程序的模块结构/关系定义。


个人建议:

尽可能使用DI。 如果你必须处理分形结构中的动态/运行时服务解析,请使用Service Locator。 将服务定位符封装为一个有作用域的DI,例如: 通过接口定位服务,而不是通过类/构造函数。


详细信息:https://learn.microsoft.com/zh-cn/dotnet/core/extensions/dependency-injection-guidelines#recommendations

以下简单的概念让我更清楚地理解了Service Locator和DI Container的区别:

服务定位器用于消费者,它根据直接消费者的请求按ID从一些存储中提取服务 DI容器位于外部的某个地方,它从某个存储中获取服务并将它们推给消费者(无论是通过构造函数还是通过方法)

然而,我们只能在具体的消费者使用的背景下讨论它们之间的区别。当在组合根目录中使用Service Locator和DI Container时,它们几乎是相似的。

它们都是IoC的实现技术。还有其他实现控制反转的模式:

工厂模式 服务定位器 DI (IoC)容器 依赖注入 (构造函数注入,参数注入(如果不需要),接口注入的setter注入) ...

服务定位器和DI容器看起来更相似,它们都使用容器来定义依赖关系,将抽象映射到具体实现。

主要的区别是依赖关系是如何定位的,在服务定位器中,客户端代码请求依赖关系,在DI容器中,我们使用容器来创建所有对象,并将依赖关系作为构造函数参数(或属性)注入。

DI容器是服务定位器的超集。它可用于定位服务,并具有组装(连接)依赖项注入的附加功能。

Martin Fowler说:

使用服务定位器,应用程序类将显式地通过 消息发送给定位器。对于注入,没有显式的请求, 服务出现在应用程序类中——因此是 控制。

简而言之:服务定位器和依赖注入只是依赖反转原理的实现。

重要的原则是“依赖抽象,而不是具象”。这将使你的软件设计“松散耦合”、“可扩展”、“灵活”。

您可以使用最适合您需要的一种。对于拥有庞大代码库的大型应用程序,您最好使用服务定位器,因为依赖注入将需要对代码库进行更多更改。

你可以查看这篇文章:依赖倒置:服务定位器或依赖注入

还有经典的:Martin Fowler的控制容器反转和依赖注入模式

设计可重用类作者:Ralph E. Johnson和Brian Foote

然而,让我大开眼界的是:ASP。NET MVC:解析还是注入?这就是问题所在,迪诺·埃斯波西托著