从前有匹马叫代码
心若没有栖息的地方,到哪里都是流浪

依赖注入(Dependency Injection,DI)是一种设计模式,主要用于实现控制反转(Inversion of Control,IoC)。它通过将对象的依赖关系从内部管理转移到外部容器来解耦组件,从而提高代码的可测试性、可维护性和灵活性。

之前在使用nest.js中做开发的时候,被这种模式的简单性吸引,今天自己来使用TS简单实现一下依赖注入的能力。

首先在tsconfig.json中开启装饰器能力

 "experimentalDecorators": true

然后我需要提供一个装饰器,来标识这个类是提供服务的类,也就是说可以被注入的类,代码如下

type Services = { [key: string]: any };
const services: Services = new Map();

function injectable(target: any) {
  services.set(target.name, target);
}

我定义了一个map来存放这些可以注入的类,然后我们使用一下这个装饰器

@injectable
class MapServices {
    getLocation() {
        console.log("返回当前用户的经纬度...");
    }
}

OK,接下来,我们定义加载装饰器,用来加载这些提供依赖的服务

function inject(className: string) {
    return function (target: any, propertyKey: string) {
        if (services.get(className)) {
            target[propertyKey] = new (services.get(className))();
        } else throw new ReferenceError(`${className}的依赖无法找到!`);
    };
}

然后,我们使用这个装饰器来将提供地图服务的依赖加载进来

class UserController {
    @inject("MapServices") mapServices?: MapServices;
    getUserLocation() {
        this.mapServices!.getLocation();
    }
}

最后让我们来实验一下效果

 至此,一个简单的依赖注入模式就实现了

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

2024-08-05 

突然想到一个问题,我这里所有的服务都不是单例,这样多个类注入的时候会产生多个实例,不是很好,那我来优化下,让他们注入的都是同一个对象就好了

首先将@injectable装饰器进行修改

function injectable(target: any) {
    services.set(target.name, new target());
}

然后,修改@inject装饰器

function inject(className: string) {
    return function (target: any, propertyKey: string) {
        if (services.get(className)) {
            target[propertyKey] = services.get(className);
        } else throw new ReferenceError(`${className}的依赖无法找到!`);
    };
}

这样,多个类注入的服务就是同一个实例了,Nice

 

posted on 2024-08-02 14:49  从前有匹马叫代码  阅读(93)  评论(0编辑  收藏  举报