返回

剖析 TypeScript 装饰器的依赖注入机制

后端

TypeScript 中的装饰器

装饰器是 TypeScript 中的一项重要特性,它允许我们在不修改源代码的情况下,为类、方法、属性或参数添加额外的功能或元数据。装饰器通过在类、方法或属性声明之前使用 @ 符号来定义。

依赖注入 (DI)

依赖注入 (DI) 是一种设计模式,它可以将对象的创建和使用分离,从而提高代码的可测试性和可维护性。在 DI 中,对象不负责创建其依赖项,而是由一个中央组件(通常称为依赖注入容器)来负责。这样,当我们需要更改依赖项时,我们只需要修改依赖注入容器的配置,而不需要修改代码本身。

TypeScript 中的装饰器实现 DI

在 TypeScript 中,我们可以通过装饰器来实现 DI。我们可以创建一个装饰器,该装饰器可以将一个类标记为需要被注入依赖项。当该装饰器被应用到一个类上时,依赖注入容器会自动创建该类的实例,并将其注入到需要它的类中。

以下是一个简单的示例,展示了如何使用装饰器实现 DI:

// 定义一个装饰器,该装饰器可以将一个类标记为需要被注入依赖项
const Injectable = () => (target: any) => {
  // 将该类标记为需要被注入依赖项
  Reflect.defineMetadata('isInjectable', true, target);
};

// 定义一个类,该类需要被注入依赖项
@Injectable()
class Service {
  // 构造函数
  constructor() {
    // ...
  }

  // 方法
  public doSomething() {
    // ...
  }
}

// 定义一个类,该类依赖于 Service 类
class Controller {
  // 构造函数
  constructor(private service: Service) {
    // ...
  }

  // 方法
  public doSomething() {
    // 调用 Service 类的方法
    this.service.doSomething();
  }
}

// 定义一个依赖注入容器
const container = new Container();

// 将 Service 类注册到依赖注入容器中
container.register(Service);

// 将 Controller 类注册到依赖注入容器中
container.register(Controller);

// 从依赖注入容器中获取 Controller 类的实例
const controller = container.get(Controller);

// 调用 Controller 类的方法
controller.doSomething();

在这个示例中,我们首先定义了一个 Injectable 装饰器,该装饰器可以将一个类标记为需要被注入依赖项。然后,我们将这个装饰器应用到 Service 类上,表明 Service 类需要被注入依赖项。

接下来,我们定义了一个 Controller 类,该类依赖于 Service 类。在 Controller 类的构造函数中,我们将 Service 类作为参数传入,表明 Controller 类需要依赖 Service 类。

最后,我们定义了一个依赖注入容器 container,并使用它来注册 Service 类和 Controller 类。当我们从依赖注入容器中获取 Controller 类的实例时,依赖注入容器会自动创建 Service 类的实例并将其注入到 Controller 类中。

这样,我们就通过装饰器实现了 DI,从而使代码更加模块化、易于维护和测试。