Dependencty Injection
依赖注入 DI 是一个
OOP变成是基于实例instance 和 类Class 的,如果要使用功能,需要先实例化才能调用功能
遵循单一职责,复杂代码不会都写在一起,会分离多个子模块。
我们希望不同模块之间耦合度不要太高,如果底层模块发生变化,整个程序的改动会非常多,可靠性下降。
import B from ‘../def/B’;
import createC from ‘../def/C’;
class A{
constructor(paramB, paramC){
this.b = new B(paramB);
this.c = createC(paramC);
}
actionA(){
this.b.actionB();
}
}
代码风格不好,A除了需要承担其本身的职责之外,还额外承担了B和C的实例化任务
如果对actionA方法进行单元测试,理论上只要actionB方法执行正确,实际上已经变成了包含B实例化过程、C实例化过程以及actionB方法调用的小范围集成测试
依赖注入DI就是为了解决上述问题,这种编程模式中,在构造函数里接收已经实例化好了的对象
class A{
constructor(bInstance, cInstance){
this.b = bInstance;
this.c = cInstance;
}
actionA(){
this.b.actionB();
}
}
这种时候,实例化过程在外部,A只需要专注自己的逻辑。
实例化在外部,这个外部称为容器,类似于 类注册表+工厂方法。用key-value 的注册表把各个类容器注册到容器里。
再让容器来控制类的实例化过程,如果需要用到实例的时候,容器会自动对依赖分析,生成需要的实例注入到构造函数中。当然会缓存
在这种模式下,强依赖消失了,不过传入的实例是啥,只要有对应的方法就行。鸭式辨形,说的就是这里了,ts里通过interface约束就完了。
DI实际上是 IOC的一种体现
DI:
- 上层模块不应该依赖底层模块,应该依赖共同的抽象
- 抽象不应该依赖细节,细节依赖抽象
从手动生成变成了 容器自动分析并注入,降低了耦合,隐藏了细节。也让清晰的代码晦涩,但对需求不确定有了抵御能力。
// IOC成员属性 接口1
interface iIOCMember {
factory: Function;
singleton: boolean;
instance?: {}
}
// 定义IOC容器
Class IOC {
// 私有 map实例
// PropertyKey类型,这是Typescript中预设的类型,
// 指string | number | symbol的联合类型,也就我们平时用作键的类型
private container: Map<PropertyKey, iIOCMember>;
constructor() {
this.container = new Map<string, iIOCMember>();
}
}
参考