服务定位器 vs. 依赖注入

6

我正在审查一些类似于以下代码的语句:

private SomeInterface x = Locator.getInstance(SomeInterface.class)

我期望看到类似以下的内容:
private SomeInterface x;

@Inject
public Consumer(SomeInterface x){ // constructor
    this.x = x;
}

第一种方法有什么问题吗?好的,依赖关系不是很明显,但实现可以通过定位器的配置轻松地进行交换。


https://steveschols.wordpress.com/2012/05/14/dependency-injection-vs-service-locator/#comment-539 - Kanagavelu Sugumar
4个回答

11

Martin Fowler写了一篇关于DI与Locators的文章

支持DI的理由:

  • 更容易确定组件所依赖的内容——只需查看构造函数。
  • 组件不依赖于服务定位器,因此如果使用不同的框架,就不存在问题。
  • DI可能使测试更加容易,但良好的服务定位器机制将使存根同样可行。

反对DI的理由:

  • 更难调试和理解。
  • 一旦配置完成,组件无法从注入器请求额外的服务。

我个人认为第一种基于定位器的方法并没有什么本质上的问题——尽管我猜DI可以标准化这个过程,所以如果有的话我会使用它。所有好的想法最终都会成为框架,这就是在这里发生的事情。而且,使用DI您可以利用其他注释、范围等,而无需编写自己的代码。在我看来,项目使用的定制代码越少越好。但是,我还是把最后的话留给Fowler:

选择服务定位器还是依赖注入的选择并不重要,重要的是将服务配置与应用程序中使用服务的原则分开。


6

第一个例子:x = Locator.getInstance(SomeInterface.class) 看起来像是服务定位器模式,而http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx 这篇文章指出了 服务定位器是一种反模式,应该避免使用。

对于第二个用法,我喜欢构造函数注入,它的实现非常流畅。但是我不想使用属性(Java中的注释?),因为任何时候我都可能想要更改我正在使用的依赖注入容器,我不想从所有类中删除属性。


2
@Inject 在 Java 中由 JSR-330 标准化。 - deamon
@deamon,我以为那只是CrazyBob的DI注释。不知道它被接受为语言标准了。谢谢您提供的信息。 - adt
此外:Java 上下文和依赖注入(CDI) 定义在 JSR 299JSR 346JSR 365 中。现在在 Jakarta.ee 维护为 Jakarta 上下文和依赖注入 - Basil Bourque

2

服务定位器模式使用一个称为“服务定位器”的中央注册表,该注册表在请求时返回执行某项任务所需的信息。

以下是服务定位器设计模式的最坏方面:

  • 放置在注册表中的内容对于系统的其余部分来说实际上是黑盒子。这使得更难以检测和恢复它们的错误,并可能使整个系统不太可靠。

  • 注册表必须是唯一的,这可能会使它成为并发应用程序的瓶颈。

  • 注册表可能是严重的安全漏洞,因为它允许外部人员将代码注入到应用程序中。

  • 无法通过构造函数传递依赖项(如DI模式中所做的那样),并且难以进行单元测试。

在我看来,只有在应用程序的顶层使用服务定位器设计模式才是可接受的,当您的服务定位器可能不会改变时。


1

服务定位器模式本身并没有什么“错”的问题,

在这种情况下,支持DI的一个主要论点将是可测试性。

毫无疑问,DI可实现更好的单元测试。Locator上的静态getInstance方法使其更难以独立地进行测试。


这不仅仅是单元测试。Mark Seemann已经非常清楚地描述了这一点:http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx。 - Steven
4
不想进行这种哲学讨论 :) 在我看来,“反模式”是一个过度使用的说法。我个人也支持 DI,但我不会在代码审查期间将其标记为反模式。 - ddewaele
我在几年前的一个项目中引入了IoC(以服务定位器模式的形式),以允许该团队开始编写测试。这是一个很好的开始,从完全无法进行测试到现在。但是,现在已经过去两年多了,到处都是这种模式,而不是使用DI,这真的非常痛苦。所以对我来说,这不再是哲学问题了。我曾经在那里,我经历过,这都是我的错。现在,我尽可能大声地呼喊,帮助其他人避免我犯过的错误。 - Steven

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接