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

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


当前回答

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

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的实现

其他回答

例如,我们有两类客户机和服务。客户端将使用服务

public class Service {
    public void doSomeThingInService() {
        // ...
    }
}

无依赖注入

方式1)

public class Client {
    public void doSomeThingInClient() {
        Service service = new Service();
        service.doSomeThingInService();
    }
}

方式2)

public class Client {
    Service service = new Service();
    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

方式3)

public class Client {
    Service service;
    public Client() {
        service = new Service();
    }
    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

1) 2)3)使用

Client client = new Client();
client.doSomeThingInService();

优势

易于理解的

缺点

难以测试客户端类当我们更改Service构造函数时,我们需要在所有位置更改代码createService对象

使用依赖注入

方式1)构造函数注入

public class Client {
    Service service;

    Client(Service service) {
        this.service = service;
    }

    // Example Client has 2 dependency 
    // Client(Service service, IDatabas database) {
    //    this.service = service;
    //    this.database = database;
    // }

    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

使用

Client client = new Client(new Service());
// Client client = new Client(new Service(), new SqliteDatabase());
client.doSomeThingInClient();

方式2)沉淀剂注入

public class Client {
    Service service;

    public void setService(Service service) {
        this.service = service;
    }

    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

使用

Client client = new Client();
client.setService(new Service());
client.doSomeThingInClient();

方式3)接口注入

检查https://en.wikipedia.org/wiki/Dependency_injection

===

现在,这段代码已经遵循了依赖注入,测试客户端类更容易。然而,我们仍然多次使用新的Service(),并且在更改Service构造函数时效果不佳。为了防止这种情况,我们可以使用DI注射器1) 简单手动喷油器

public class Injector {
    public static Service provideService(){
        return new Service();
    }

    public static IDatabase provideDatatBase(){
        return new SqliteDatabase();
    }
    public static ObjectA provideObjectA(){
        return new ObjectA(provideService(...));
    }
}

使用

Service service = Injector.provideService();

2) 使用库:适用于Android dagger2

优势

使测试更容易更改服务时,只需在Injector类中更改如果您使用使用构造函数注入,当您查看Client的构造函数时,您将看到Client类有多少依赖项

缺点

如果使用构造函数注入,则在创建客户端时创建服务对象,有时我们在客户端类中使用函数而不使用服务,因此创建的服务被浪费

依赖注入定义

https://en.wikipedia.org/wiki/Dependency_injection

依赖项是可以使用的对象(服务)注入是将依赖项(Service)传递给将使用它的依赖对象(Client)

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

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

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

针对5岁儿童的依赖注入。

当你自己去把冰箱里的东西拿出来时,你可能会引起问题。你可能会让门开着,你可能会得到妈妈或爸爸不希望你拥有的东西。你甚至可能在寻找我们甚至没有或已经过期的东西。

你应该做的是陈述一个需要,“我需要午餐时喝点东西”,然后我们会确保你坐下吃饭时有东西。

使依赖注入概念易于理解。让我们以开关按钮为例来切换(打开/关闭)灯泡。

无依赖注入

Switch需要事先知道我连接到哪个灯泡(硬编码依赖项)。所以

开关->永久灯泡//开关直接连接到永久灯泡,测试不容易

Switch(){
PermanentBulb = new Bulb();
PermanentBulb.Toggle();
}

使用依赖注入

开关只知道我需要打开/关闭传递给我的灯泡。所以,

开关->灯泡1或灯泡2或夜灯泡(注入依赖性)

Switch(AnyBulb){ //pass it whichever bulb you like
AnyBulb.Toggle();
}

修改开关和灯泡的James示例:

public class SwitchTest { 
  TestToggleBulb() { 
    MockBulb mockbulb = new MockBulb(); 

    // MockBulb is a subclass of Bulb, so we can 
    // "inject" it here: 
    Switch switch = new Switch(mockBulb); 

    switch.ToggleBulb(); 
    mockBulb.AssertToggleWasCalled(); 
  } 
}

public class Switch { 
  private Bulb myBulb; 

  public Switch() { 
    myBulb = new Bulb(); 
  } 

  public Switch(Bulb useThisBulbInstead) { 
    myBulb = useThisBulbInstead; 
  } 

  public void ToggleBulb() { 
    ... 
    myBulb.Toggle(); 
    ... 
  } 
}`

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

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

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

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

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

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

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

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