前端需要了解的依赖注入

作为前端,会经常碰到依赖注入,对于其原理还不是很了解,作为一个学习者,在阅读了大量依赖注入相关文档后,以前端更能理解的方式来表达,所以本身对依赖注入的了解不是很深入,旨在帮助前端的同学理解。

依赖注入基本概念

依赖注入是指让一个对象 A 作为另一个对象 B 的依赖,使 B 能使用 A。

从上面这句话应该能明白三个问题:什么是依赖?注入到什么里边?

在注入关系中,依赖可以被注入到很多其他对象中,相当于「服务端」,而接受注入的那个对象能够被注入(接受)很多依赖,相当于「客户端」。有了服务端和客户端,还需要「注射器」将服务端的内容发送(注射)到客户端。需要注意的是,依赖注入模式要求将「服务端」注入「客户端」,即「客户端」是被注入的关系。

为什么需依赖注入

这得谈一下依赖注入和解耦的关系,可以参考这篇文章的内容,这篇文章理清了控制反转(IOC)、依赖注入(DI)和耦合的关系。系统的耦合之处在于各个组件之间相互依赖,有的时候会相互引用甚至要创建依赖的部分,解耦的一个方法就是不让这些耦合组件直接相互调用,而是在使用的时候从一个中心取用,而中心再去找到真正需要调用的模块,这样每个组件只需要和中心进行交流,从而避免了组件之间高度耦合。

在解耦之前,引用依赖的过程就类似于自助,而有了一个统一的中心之后类似于有人提供服务,对于组件来说权限更小了。

2004 年,Martin Fowler 探讨了同一个问题,既然 IOC 是控制反转,那么到底是“哪些方面的控制被反转了呢?”,经过详细地分析和论证后,他得出了答案:“获得依赖对象的过程被反转了”。控制被反转之后,获得依赖对象的过程由自身管理变为了由 IOC 容器主动注入。于是,他给“控制反转”取了一个更合适的名字叫做“依赖注入(Dependency Injection)”。他的这个答案,实际上给出了实现 IOC 的方法:注入。所谓依赖注入,就是由 IOC 容器在运行期间,动态地将某种依赖关系注入到对象之中。

所以控制反转是实现解耦的一种理念,而依赖注入则是控反转的具体实现。

依赖注入的几种方式

依赖注入的核心就是,所有依赖都不是自己的,而是从外边拿的。把依赖当作一个对象变量,要满足这个条件,可以用三种方式实现:

  1. 通过构造函数注入
  2. 通过对象方法来设置

假设依赖是这样:

JavaScript
1
2
3
class Dep {
name = "dep";
}

每一个模块就可以这样写:

方式一

JavaScript
1
2
3
4
5
6
7
8
9
class ModA {
constructor(dep) {
this.dep = dep;
}
}

// 使用
let dep = new Dep();
let a = new ModA(dep);

注意是传入一个已经实例化的依赖,而不是自己实例化依赖。

方式二

JavaScript
1
2
3
4
5
6
7
8
9
10
class ModA {
getDep(dep) {
this.dep = dep;
}
}

// 使用
let a = new ModA();
let dep = new Dep();
a.setDep(dep);

当改变dep属性的时候a中的dep属性也会跟着变化,这样使用这些依赖就不用再考虑如何改变依赖,控制权并不在模块之中。

和上一种方式大同小异,只是绑定依赖的时刻不一样,本质上都是传递一个在外部实例化的对象。

依赖注入实现

上面代码提供了思路,但对于一个系统来说是并不完整的,上面的代码体现了几点问题:

  1. 每次都需要单独写一段代码来手动初始化依赖,虽然不是在模块内部初始化,但是不太简洁
  2. 第一个问题就导致了,有大量依赖的时候不便于管理

真正的依赖注入还需要一个服务中心来进行管理和依赖分发,就像之前所说的那样。

一个服务中心,至少需要实现两个功能:

  1. 服务注册,创建一个容器用于存放依赖
  2. 注入服务

服务注册这个地方可以使用一个对象来存储,注入服务可以让模块统一暴露设置接口,通过接口来设置依赖。

参考资料

  1. 深入浅出依赖注入
  2. 什么是依赖注入
  3. Dependency injection - Wikipedia

相关阅读

  1. 依赖注入系列教程
  2. Dependency Injection - jenkov.com
  3. Inversion of Control Containers and the Dependency Injection pattern
  4. What is Dependency Injection? - Fabien Potencier
作者

KylinLee

发布于

2021-04-29

更新于

2022-02-11

许可协议

CC BY-NC-SA 4.0

评论

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×