<aside> 😀
</aside>
“控制反转”是一种软件设计原则。可以用一个简单的类比来理解,就好像你原本自己负责准备晚餐(自己创建和管理对象),现在变成了别人为你准备好晚餐并端给你(对象的创建和管理由框架或其他外部机制来负责)。在编程中,控制反转意味着控制权从应用程序代码转移到了外部的框架或容器,使得程序的结构更加灵活和可扩展。 但对于编程新手来说,这个概念可能比较抽象和难以一下子理解。
最经典的方法是基于依赖注入(DI)的控制反转(IoC)
首先, 这是使用装饰器实现的,所以要了解一下装饰器的使用:
开始之前,我打算参考Nestjs的装饰器用法,使用@Injectable
和@Inject
实现依赖注入的声明。
1 先写一个简单的依赖注入管理容器di_container
,负责控制反转的托管
const di_container = {
// 存储记录的实例原型
injects: {
} as {[key:string]: Function},
// 存储每个原型的实例, 这里只考虑单例的情况
instance: {
} as {[key:string]: any},
// 记录没有原型的依赖关系
depsMap: {
} as {[key:string]: Map<string, Function>},
get(_class: Function) {
const class_name = _class.name;
if (this.instance[class_name]) {
return this.instance[class_name];
}
const deps = this.depsMap[class_name] as Map<string, Function> | undefined;
const _prototype = this.injects[class_name]
const instance = new _prototype();
this.instance[class_name] = instance;
if (deps) {
[...deps.entries()].forEach(([attr, injector]) => {
instance[attr] = this.get(injector);
})
}
return instance;
}
}
然后,编写@Injectable
和@Inject
装饰
// 类装饰器
// 负责把类原型放置到injects.di_container
function Injectable(target: Function) {
di_container.injects[target.name] = target
}
// 属性装饰器
// 负责记录依赖表di_container.depsMap
function Inject(inject: Function) {
return function (target: any, attr: string) {
if (!di_container.depsMap[target.constructor.name]) {
di_container.depsMap[target.constructor.name] = new Map();
}
di_container.depsMap[target.constructor.name].set(attr, inject);
}
}