【设计模式】依赖注入和控制反转
2023/11/30 23:40:372022/12/08 16:45:52
依赖注入 DI 和控制反转 IOC
依赖注入(DI)和控制反转(IOC)基本是一个意思,因为说起来谁都离不开谁。 ——知乎回答中的评论
本来我接受各种参数来构造一个对象,现在只接受一个参数——已经实例化的对象。 ——同回答下的另一个评论
依赖项注入(DI)是一种设计模式,在这种设计模式中,类会从外部源请求依赖项而不是创建它们。 ——Angular 中的依赖注入
什么是依赖注入/控制反转
假设有两个类 A 和 B,如果要在 A 中调用 B 的成员方法,就要先在 A 中 new
一个 B 的实例,如果 A 中的多个方法中都需要调用 B 的成员方法,就要调用多个 new
。
class A {
text1() {
const b = new B();
b.show();
}
text2() {
const b = new B();
b.show();
}
}
class B {
show()
}
这样的实现方式会导致 A 和 B 紧密耦合在一起。
这时候通过一个第三方来执行 new B()
的操作,这叫做控制反转。
A 要依赖 B,必然要使用 B 的实例:
- 通过 A 的接口,把 B 的实例传入。
- 通过 A 的构造,把 B 的实例传入。
- 通过设置 A 的属性,把 B 的治理传入。
将 B 的实例传入 A 的过程就叫依赖注入。
用传入实例的方式让 A 可以使用 B 的实例,这就是依赖注入,这让 A 和 B 两个类解耦。
由第三方控制实例的构造和销毁,这就是控制反转。
为什么要用依赖注入
通过控制反转和依赖注入,可以让相互依赖的类减少耦合。
可以减少重复的 new B()
代码。
怎么用依赖注入
依赖注入是一种设计模式,一些框架中实现了自己的 DI 框架,可以用他们提供的方式使用。
实现一个简单的依赖注入模式
未使用依赖注入模式时的依赖关系
ClassA
提供两个方法:submit()
和 getInfo()
// a.js
export class ClassA {
submit()
getInfo()
}
如果其他模块要使用这两个方法,需要导入并实例化 ClassA
:
// b.js
import {ClassA} from './a.js'
const classA = new ClassA()
export class classB {
constructor() {
classA.getInfo()
}
}
main
函数
// main.js
import {ClassB} from './b.js'
new ClassB()
这样的副作用就是 ClassB
完全依赖 ClassA
,这就形成了耦合。
使用依赖注入后的依赖关系
改造 ClassB
// b.js
export class classB {
constructor(classA) {
classA.getInfo()
}
}
改造 main
import {ClassA} from './a.js'
import {ClassB} from './b.js'
const classA = new ClassA()
const classB = new ClassB(classA)
像这样,在 main
中将实例 classA
传递给 ClassB
,就实现了 ClassB
和 ClassA
的解耦。