<aside> 😀

</aside>

📝 控制反转

“控制反转”是一种软件设计原则。可以用一个简单的类比来理解,就好像你原本自己负责准备晚餐(自己创建和管理对象),现在变成了别人为你准备好晚餐并端给你(对象的创建和管理由框架或其他外部机制来负责)。在编程中,控制反转意味着控制权从应用程序代码转移到了外部的框架或容器,使得程序的结构更加灵活和可扩展。 但对于编程新手来说,这个概念可能比较抽象和难以一下子理解。

IoC有何实现方式?

最经典的方法是基于依赖注入(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);
    }
}