Java 服务定位器与依赖注入

Java 服务定位器与依赖注入,java,dependency-injection,factory-pattern,Java,Dependency Injection,Factory Pattern,我正在用很多这样的语句来检查代码: private SomeInterface x = Locator.getInstance(SomeInterface.class) 我期待着类似的事情 private SomeInterface x; @Inject public Consumer(SomeInterface x){ // constructor this.x = x; } 第一种方法有问题吗?好的,依赖关系不是很明显,但是可以通过配置定位器轻松地交换实现。第一个示例: get

我正在用很多这样的语句来检查代码:

private SomeInterface x = Locator.getInstance(SomeInterface.class)
我期待着类似的事情

private SomeInterface x;

@Inject
public Consumer(SomeInterface x){ // constructor
    this.x = x;
}
第一种方法有问题吗?好的,依赖关系不是很明显,但是可以通过配置定位器轻松地交换实现。

第一个示例: getInstance(SomeInterface.class)看起来像服务定位器模式,检查本文,它说服务定位器是一种反模式,应该避免

对于第二个用法,它非常好,我喜欢构造函数注入,它平滑而精细的实现。但是我不想使用属性(Java中的注释),因为任何时候我都可能想更改我正在使用的DI容器,并且我不想从所有类中删除属性。

Martin Fowler写道:

对于DI:

  • 更容易确定组件具有哪些依赖关系-查看 构造器
  • 组件不依赖于服务定位器,因此不存在 如果组件与一起使用,则会出现问题 一个不同的框架
  • DI可能使测试更容易,但一个好的服务定位器机制将使测试更容易 使存根同样可行
反对直接投资:

  • 更难调试和理解
  • 组件一旦启动,就无法从injector请求额外服务 已配置
我个人并不认为第一种基于定位器的方法有什么本质上的不好之处——我想DI确实将其标准化了,所以如果它可用,我会使用它。所有好的想法都会在某个时候以框架的形式结束,所以这里发生了这样的事情。此外,使用DI,您可以利用其他注释、作用域等,而无需滚动自己的代码。您的项目使用的定制代码越少,IMO就越好。不过,我将把最后一句话留给Fowler:

服务定位器和服务定位器之间的选择 依赖注入不那么重要 而不是分离原则 从使用 应用程序中的服务

服务定位器模式本身没有“错误”

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

毫无疑问,DI允许更好的单元测试。Locator上的静态getInstance方法使得隔离测试更加困难。

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

这些是服务定位器设计模式最糟糕的一面:

  • 放置在注册表中的东西实际上是带有 关于系统的其余部分。这使得它更难检测和识别 从错误中恢复,并可能使整个系统更少 可靠

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

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

  • 无法通过构造函数传递依赖项(就像我们在DI模式中所做的那样),并且很难进行单元测试


我认为只有在应用程序的顶层使用服务定位器设计模式是可以接受的,因为您的服务定位器可能不会更改。

@Inject
是由@deamon在Java中标准化的,我认为这只是CrazyBob的DI注释。我不知道它被认为是语言标准。谢谢你的信息。另外:定义在,和。现在维护在as。不仅仅是单元测试。马克·希曼(MarkSeemann)对此做了非常清楚的描述:。他想避免这种哲学讨论:)“反模式”是一种被过度使用的说法。我个人也支持DI,但我不会在代码审查期间将其标记为反模式。几年前,我在一个项目中引入了IoC(以服务定位器模式的形式),以允许该团队开始编写测试。这是一个很好的开始,因为根本无法进行测试。但是现在,两年多之后,到处都是这种模式而不是使用DI是一种真正的痛苦。所以对我来说,这不再是哲学。我去过那里,我经历过,这都是我的错。这些天来,我尽力尖叫,帮助别人避免犯我犯的错误。