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

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


当前回答

我们可以实现依赖注入来了解它:

class Injector {
  constructor() {
    this.dependencies = {};
    this.register = (key, value) => {
      this.dependencies[key] = value;
    };
  }
  resolve(...args) {
    let func = null;
    let deps = null;
    let scope = null;
    const self = this;
    if (typeof args[0] === 'string') {
      func = args[1];
      deps = args[0].replace(/ /g, '').split(',');
      scope = args[2] || {};
    } else {
      func = args[0];
      deps = func.toString().match(/^function\s*[^\(]*\(\s*([^\)]*)\)/m)[1].replace(/ /g, '').split(',');
      scope = args[1] || {};
    }
    return (...args) => {
      func.apply(scope || {}, deps.map(dep => self.dependencies[dep] && dep != '' ? self.dependencies[dep] : args.shift()));
    }
  }
}

injector = new Injector();

injector.register('module1', () => { console.log('hello') });
injector.register('module2', () => { console.log('world') });

var doSomething1 = injector.resolve(function (module1, module2, other) {
  module1();
  module2();
  console.log(other);
});
doSomething1("Other");

console.log('--------')

var doSomething2 = injector.resolve('module1,module2,', function (a, b, c) {
  a();
  b();
  console.log(c);
});
doSomething2("Other");

以上是javascript的实现

其他回答

我在松耦合方面发现了一个有趣的例子:

来源:了解依赖注入

任何应用程序都由许多对象组成,这些对象相互协作以执行一些有用的任务。传统上,每个对象都负责获取自己对与其协作的依赖对象(依赖关系)的引用。这导致了高度耦合的类和难以测试的代码。

例如,考虑Car对象。

汽车依靠轮子、发动机、燃料、电池等运转。传统上,我们定义此类依赖对象的品牌以及Car对象的定义。

无依赖注入(DI):

class Car{
  private Wheel wh = new NepaliRubberWheel();
  private Battery bt = new ExcideBattery();

  //The rest
}

在这里,Car对象负责创建从属对象。

如果我们希望在初始NepaliRubberWheel()穿孔后更改其从属对象的类型(例如Wheel),该怎么办?我们需要重新创建Car对象及其新的依赖项,例如ChineseRubberWheel(),但只有Car制造商才能做到这一点。

那么依赖注入为我们做了什么。。。?

当使用依赖注入时,对象在运行时而不是编译时(汽车制造时)被赋予依赖性。因此,我们现在可以随时更改轮子。在这里,相关性(轮子)可以在运行时注入Car。

使用依赖注入后:

这里,我们在运行时注入依赖项(Wheel和Battery)。因此有了这个词:依赖注入。我们通常依赖于Spring、Guice、Weld等DI框架来创建依赖关系并在需要时注入。

class Car{
  private Wheel wh; // Inject an Instance of Wheel (dependency of car) at runtime
  private Battery bt; // Inject an Instance of Battery (dependency of car) at runtime
  Car(Wheel wh,Battery bt) {
      this.wh = wh;
      this.bt = bt;
  }
  //Or we can have setters
  void setWheel(Wheel wh) {
      this.wh = wh;
  }
}

其优点是:

分离对象的创建(换句话说,将使用与对象的创建分开)能够替换依赖项(例如:车轮、电池),而不改变使用它的类(汽车)促进“代码到接口而不是实现”原则在测试期间创建和使用模拟依赖关系的能力(如果我们想在测试期间使用模拟轮而不是真实实例,我们可以创建模拟轮对象并让DI框架注入Car)

来自Christoffer Noring,Pablo Deeleman的书《学习角度-第二版》:

“随着我们的应用程序的增长和发展,我们的每一个代码实体都将在内部需要其他对象的实例,在软件工程领域中,这些对象被称为依赖关系。将这些依赖关系传递给依赖客户端的动作被称为注入,它还需要另一个代码主体(称为注入器)的参与。注入器将负责用于实例化和引导所需依赖项的功能,以便它们从成功注入客户端的那一刻起就可以使用。这一点非常重要,因为客户机不知道如何实例化自己的依赖关系,只知道为了使用它们而实现的接口。"

发件人:Anton Moiseev。《字体角度发展,第二版》一书:

“简而言之,DI帮助您以松散耦合的方式编写代码,并使代码更易于测试和重用。”

依赖注入是与Spring框架相关概念的核心。在创建任何项目的框架时,Spring都可能发挥重要作用,而依赖注入就是其中之一。

实际上,假设在java中,您创建了两个不同的类,即类A和类B,并且无论类B中有什么函数,您都希望在类A中使用,所以此时可以使用依赖注入。在这里,您可以将一个类的对象放入另一个类中,就像您可以将整个类注入另一个类别中以使其可访问一样。通过这种方式可以克服依赖性。

依赖注入只是将两个类粘合在一起,同时保持它们的分离。

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

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

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

摘自《扎实的Java开发人员:Java 7和多语言编程的关键技术》一书

DI是IoC的一种特殊形式,因此查找依赖项的过程是不受当前执行代码的直接控制。