已经发布了几个关于依赖注入的具体问题,例如何时使用它以及它有什么框架,

什么是依赖注入,何时/为什么应该或不应该使用它?


当前回答

依赖注入意味着一种方式(实际上是任何方式),代码的一部分(例如类)可以以模块化的方式访问依赖项(代码的其他部分,例如它所依赖的其他类),而不必对它们进行硬编码(因此它们可以自由更改或重写,甚至可以根据需要在其他时间加载)

(顺便说一句,是的,对于一个相当简单的概念,它已经成为一个过度炒作的25美元的名字),我的25美分

其他回答

这意味着对象应该只具有完成其工作所需的依赖项,并且依赖项应该很少。此外,如果可能的话,对象的依赖关系应该是接口,而不是“具体”对象。(具体对象是用关键字new创建的任何对象。)松散耦合促进了更高的可重用性,更容易维护,并允许您轻松地提供“模拟”对象来代替昂贵的服务。

“依赖注入”(DI)也称为“控制反转”(IoC),可以用作鼓励这种松散耦合的技术。

实施DI有两种主要方法:

构造函数注入设值注入

构造函数注入

这是一种将对象依赖关系传递给构造函数的技术。

注意,构造函数接受接口而不是具体对象。此外,请注意,如果orderDao参数为空,则会引发异常。这强调了接受有效依赖的重要性。在我看来,构造函数注入是赋予对象依赖关系的首选机制。在调用对象时,开发人员很清楚需要向“Person”对象提供哪些依赖关系才能正确执行。

沉淀剂注入

但是考虑下面的例子……假设您有一个类,它有十个没有依赖关系的方法,但是您要添加一个新方法,它确实依赖于IDAO。您可以将构造函数更改为使用构造函数注入,但这可能会迫使您更改所有的构造函数调用。或者,您可以添加一个新的构造函数来获取依赖项,但是开发人员如何轻松地知道何时使用一个构造函数而不是另一个构造函数。最后,如果依赖项的创建成本很高,为什么要创建它并传递给构造函数,因为它可能很少使用?“Setter Injection”是另一种DI技术,可用于此类情况。

Setter注入不会强制将依赖项传递给构造函数。相反,依赖项被设置到需要的对象公开的公共财产上。正如前面所暗示的,这样做的主要动机包括:

支持依赖注入而无需修改遗留类的构造函数。允许在需要时尽可能晚地创建昂贵的资源或服务。

下面是上述代码的示例:

public class Person {
    public Person() {}

    public IDAO Address {
        set { addressdao = value; }
        get {
            if (addressdao == null)
              throw new MemberAccessException("addressdao" +
                             " has not been initialized");
            return addressdao;
        }
    }

    public Address GetAddress() {
       // ... code that uses the addressdao object
       // to fetch address details from the datasource ...
    }

    // Should not be called directly;
    // use the public property instead
    private IDAO addressdao;

公认的答案是一个好答案——但我想补充一点,DI非常像代码中避免硬编码常量的经典做法。

当您使用诸如数据库名称之类的常量时,您可以将其从代码内部快速移动到某个配置文件,并将包含该值的变量传递到需要它的位置。这样做的原因是,这些常量通常比代码的其他部分更频繁地更改。例如,如果您想在测试数据库中测试代码。

在面向对象编程的世界中,DI与此类似。那里的值而不是常量文字是整个对象-但是将创建它们的代码从类代码中移出的原因是相似的-对象的更改比使用它们的代码更频繁。一个重要的情况是需要进行这样的改变,那就是测试。

什么是依赖注入?

依赖注入(DI)意味着分离彼此依赖的对象。假设对象A依赖于对象B,因此想法是将这些对象彼此分离。我们不需要使用new关键字对对象进行硬编码,而是在运行时共享对对象的依赖关系,而不管编译时间如何。如果我们谈论

依赖注入在Spring中的工作原理:

我们不需要使用new关键字硬编码对象,而是在配置文件中定义bean依赖关系。弹簧容器将负责连接所有部件。

控制反转(IOC)

IOC是一个通用概念,可以用多种不同的方式表达,依赖注入是IOC的一个具体例子。

两种类型的依赖注入:

构造器注入沉淀剂注入

1.基于构造函数的依赖注入:

当容器调用具有多个参数的类构造函数时,就完成了基于构造函数的DI,每个参数表示对其他类的依赖。

public class Triangle {

private String type;

public String getType(){
    return type;
 }

public Triangle(String type){   //constructor injection
    this.type=type;
 }
}
<bean id=triangle" class ="com.test.dependencyInjection.Triangle">
        <constructor-arg value="20"/>
  </bean>

2.基于Setter的依赖注入:

基于Setter的DI是在调用无参数构造函数或无参数静态工厂方法来实例化bean之后,通过容器调用bean上的Setter方法来实现的。

public class Triangle{

 private String type;

 public String getType(){
    return type;
  }
 public void setType(String type){          //setter injection
    this.type = type;
  }
 }

<!-- setter injection -->
 <bean id="triangle" class="com.test.dependencyInjection.Triangle">
        <property name="type" value="equivialteral"/>

注:对于强制依赖项使用构造函数参数,对于可选依赖项使用setter,这是一个很好的经验法则。注意,如果我们在setter上使用基于@Required的注释,则可以将setter作为必需的依赖项。

“依赖注入”不就是指使用参数化构造函数和公共setter吗?

James Shore的文章展示了以下示例进行比较。

没有依赖注入的构造函数:公共类示例{私有数据库Thingie myDatabase;public Example(){myDatabase=新数据库Thingie();} public void doStuff(){... myDatabase.getData();... } } 具有依赖注入的构造函数:公共类示例{私有数据库Thingie myDatabase;公共示例(DatabaseThingie使用ThisDatabaseReplace){myDatabase=改用此数据库;}public void doStuff(){... myDatabase.getData();... } }

依赖注入是基于框架构建的“控制反转”原则的一种实现。

GoF的“设计模式”中所述的框架是实现主控制流逻辑的类,从而使开发人员能够这样做,这样框架实现了控制原则的反转。

作为一种技术而不是作为类层次结构实现的方法,IoC原则只是依赖注入。

DI主要包括将类实例的映射和对这些实例的类型引用委托给外部“实体”:对象、静态类、组件、框架等。。。

类实例是“依赖项”,调用组件通过引用与类实例的外部绑定是“注入”。

显然,从OOP的角度来看,您可以以多种方式实现该技术,例如,构造函数注入、setter注入、接口注入。

授权第三方执行将引用与对象匹配的任务,这在您希望将需要某些服务的组件与同一服务实现完全分离时非常有用。

这样,在设计组件时,您可以只关注其体系结构和特定逻辑,信任与其他对象协作的接口,而不必担心所使用的对象/服务的任何类型的实现更改,如果您正在使用的同一对象将被完全替换(显然是尊重接口)。