关于Java:什么是依赖注入?

What is meant to be a dependency injection?

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
What is Inversion of Control?

我真的很困惑依赖注入的概念。

我对软件领域非常陌生,我对下面的场景有疑问。假设我需要为我的Java代码提供一个EDCOX1×0的解析器类,所以我在使用EDCOX1 2Ω参数执行Java程序时添加了EDCOX1×0的jar。我的程序依赖于Jsonjar,所以这意味着我在这里进行依赖注入?

另一个例子是,使用EDCOX1,4的语句确实解决了用户类依赖于其他类的问题(如Java中的EDCOX1×5),所有这些都是依赖注入的概念吗?

我在那里提出这个概念。

事先谢谢。


这与您如何将组件连接在一起有关。例如,在上面,我希望您将解析器注入到需要它的类中。例如

而不是:

1
2
3
4
5
6
public class MyParserUsingClass {
   ...
   public MyParserUsingClass() {
      this.parser = new Parser();
   }
}

你会这样做:

1
2
3
4
5
6
public class MyParserUsingClass {
   ...
   public MyParserUsingClass(Parser injectedParser) {
      this.parser = injectedParser;
   }
}

为什么这么做?使用解析器的类并不真正关心解析器来自何处,应该真正使用接口而不是具体实例。通过注入解析器,您可以根据情况提供不同的实例,模拟它进行测试等。否则类只会在内部创建它,您将无法控制它。这对于可配置组件、在网络中进行通信的组件、重量级组件等来说尤其关键。


严格意义上说,依赖注入与导入类或向类路径添加JAR文件无关。它的目的是支持编程到接口的原则,它是控制反转的一种形式。

它带来的主要好处是您的代码不依赖于显式依赖实现,而是使用抽象。您依赖于一个接口,并且该接口的某个实现类的某些实例将在运行时"注入"到您的类中(或者作为构造函数参数、某个setter,或者——在我看来是错误的选择——实例字段)。

因此,您可以更改持久性层,而不必接触服务组件中的代码,因为您的服务类只关心一些DAO/Repository接口,并且您将在hood下为它们提供不同的实现。


假设你有一个叫做daes的类,叫做MyCustomParser。现在,您希望允许在该类中插入解析器,以获得针对您将要插入的解析器类型的不同行为(JSON可能会更改,您希望使用其他方法来解析等)。因此,您应该使用一个名为(通过实例)ParseIt的方法创建一个Interface--IParser。现在,根据您希望如何进行解析,您可以使用此方法的不同实现。您所需要做的就是将这个接口传递给将使用它的类MyCustomParser(您可以在构造函数中将它作为参数传递)。在这种情况下,您将在MyCustomParser类中注入解析器。


在您的特定示例中,依赖项注入看起来像:

1
2
3
4
5
6
7
8
9
10
11
public class MyParser {
     private final JsonParser parser;

     public MyParser(JsonParser parser) {
         this.parser = parser;
     }

     public Result parse(JsonInput input) {
         Result = parser.parse(input);
     }
}

假设JsonParser是一个接口,您现在可以向MyParser提供该接口的任何实现,这不取决于您选择使用的具体实现。


依赖注入更多的是减少类必须创建其自身依赖的事物实例的实例。

依赖注入的目的是通过一些外部机制将这些依赖项"赋予"消费类。常用方法包括通过构造函数传入依赖项,或者将它们设置为类的公共"可设置"属性。

例如,通过构造函数的依赖项注入可能如下所示:

1
2
3
4
5
6
7
8
public class Parser
{
     private IJsonParser parser;

     public Parser(IJsonParser parser) {
         this.parser = parser;
     }
}

这样就不需要解析器类执行如下操作:

1
2
3
4
5
6
7
8
public class Parser
{
     private IJsonParser parser;

     public Parser() {
         this.parser = new JsonParser();
     }
}

这是基于单一责任原则——Parser类不需要负责创建JSONParser,也不需要关心它使用的特定JSONParser——它的问题只是它需要执行IJSONParser接口指定的工作,并将其留给更高的控制代码D。确定最适合做这项工作的混凝土类型。