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

依赖注入(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容器只是另一种类型的服务定位器吗?当我们有很多依赖时,我们使用依赖注入容器,这是一个细微的差别吗?


当前回答

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

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

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

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

其他回答

注意:我并不是在回答这个问题。但是我觉得这对于那些对依赖注入模式和服务定位器(反)模式感到困惑的新学习者来说是有用的。

我知道服务定位器(它现在似乎被视为反模式)和依赖注入模式之间的区别,并且可以理解每种模式的具体示例,但我对在构造函数内部显示服务定位器的示例感到困惑(假设我们正在进行构造函数注入)。

“Service Locator”通常既用作模式的名称,也用作该模式中使用的对象的名称(假设也是),以在不使用new操作符的情况下获取对象。现在,同样类型的对象也可以在组合根上用于执行依赖项注入,这就是产生混淆的地方。

需要注意的一点是,您可以在DI构造函数中使用服务定位器对象,但您没有使用“服务定位器模式”。如果将它引用为IoC容器对象,就不会那么令人困惑,因为您可能已经猜到它们本质上做的是相同的事情(如果我错了,请纠正我)。

无论它被称为服务定位器(或仅仅是定位器),还是IoC容器(或仅仅是容器),正如您所猜测的那样,它们都可能引用相同的抽象(如果我说错了,请纠正我)。只是称其为服务定位器表明将服务定位器反模式与依赖注入模式一起使用。

以我之见,将其命名为“定位器”而不是“位置”或“定位”,有时也会导致人们认为文章中的服务定位器指的是服务定位器容器,而不是服务定位器(反)模式,特别是当有一个相关的模式叫做依赖注入而不是依赖注入时。

服务定位器隐藏了依赖关系——例如,当一个对象从定位器获取连接时,你不能通过观察对象来判断它是否访问了数据库。使用依赖注入(至少是构造函数注入),依赖关系是显式的。

此外,服务定位器打破了封装,因为它们提供了对其他对象的依赖关系的全局访问点。对于service locator,和任何单例一样:

很难指定前后 客户端对象的条件 接口,因为它的工作方式 可以对实现进行干预 从外面。

使用依赖注入,一旦指定了对象的依赖项,它们就处于对象本身的控制之下。

In this oversimplified case there is no difference and they can be used interchangeably. However, real world problems are not as simple. Just assume that the Bar class itself had another dependency named D. In that case your service locator wouldn't be able to resolve that dependency and you would have to instantiate it within the D class; because it is the responsibility of your classes to instantiate their dependencies. It would even get worse if the D class itself had other dependencies and in real-world situations it usually gets even more complicated than that. In such scenarios DI is a better solution than ServiceLocator.

依赖注入和服务定位器之间有什么区别(如果有的话)?这两种模式都擅长实现Dependency Inversion原则。Service Locator模式更容易在现有代码库中使用,因为它使整体设计更松散,而无需强制更改公共接口。出于同样的原因,基于Service Locator模式的代码比基于依赖注入的等效代码可读性更差。

依赖注入模式从签名开始就明确了类(或方法)将具有哪些依赖项。因此,生成的代码更清晰,可读性更强。

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

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

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

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