什么是依赖注入和控制反转

1,015 阅读2分钟

这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战

是什么

提到后端框架,经常听到的名词就是依赖注入和控制反转,这两个被java发扬光大的概念已经成了后端框架的一个最佳实践。那么问题来了,什么是依赖注入和控制反转?

依赖注入和控制反转是对同一概念不同角度的描述。

依赖注入(dependency injection),是指组件间的依赖关系由容器在运行期决定。这里的容器通常可以认为是运行框架,如Spring,Midway等。即组件之间的依赖关系是在运行的时候由容器进行注入的。

控制反转(inversion of control),是指组件依赖的内容不在对象内部进行控制引入,而是交给容器去进行控制(即反转)。

可见依赖注入强调的是容器的主体概念;而控制反转强调的是依赖控制权的转移(从组件内部转移到容器)。

为什么

依赖注入和控制反转,是一种思想,它降低了组件与组件之间的高耦合,使整个程序体系更为灵活。让我们不需要关心资源来自何处,由谁实现,只需要通过简单的配置,就能指定目标需要的资源,提高系统的灵活性及可扩展性。

实现

下面实现了一个简单的依赖注入的容器。简单介绍下实现的原理。

  1. 初始化容器的时候,执行init方法,检索文件,把类和类的内容存到一张映射表里
  2. 运行的时候,使用到某个类,调用get方法,先从缓存里查找,有直接返回
  3. 缓存没有,将这个类加入到缓存中,并对它的依赖进行递归处理
const globby = require('globby');
const path = require('path');

class Container {

  cwd = process.cwd();
  cache = {};
  classTable = {};

  init() {
    const fileResults = globby.sync(['**/**.ts', '**/**.js'], {
      cwd: this.cwd,
      ignore: [
        '**/node_modules/**',
      ],
    });

    for (const name of fileResults) {
      const exports = require(this.cwd + '/' + name);
      this.classTable[this.getName(exports)] = exports;
    }
  }

  getName(Module) {
    return Module.name.toLowerCase();
  }

  get(Module) {
    if(this.cache[this.getName(Module)]) {
      return this.cache[this.getName(Module)];
    }

    const obj = new Module();
    this.cache[this.getName(Module)] = obj;
    const properties = Object.getOwnPropertyNames(obj);
    for(let p of properties) {
      if(!obj[p]) {
        if(this.classTable[p]) {
          obj[p] = this.get(this.classTable[p]);
        }
      }
    }
  }
}

const container = new Container();
const a = container.get(A);

参考