MST

星途 面试题库

面试题:TypeScript装饰器模式的依赖注入实现

假设你正在开发一个基于TypeScript的Web应用,需要实现依赖注入功能。请使用装饰器模式,设计一个装饰器,能够将一个服务类注入到目标类的指定属性中。并说明在实际项目中,这种依赖注入方式相较于传统方式有哪些优势和可能的劣势。
37.6万 热度难度
前端开发TypeScript

知识考点

AI 面试

面试题答案

一键面试

实现装饰器

// 定义装饰器
function Inject(serviceClass: new () => any) {
    return function (target: any, propertyKey: string) {
        const serviceInstance = new serviceClass();
        Object.defineProperty(target, propertyKey, {
            value: serviceInstance,
            writable: true,
            enumerable: true,
            configurable: true
        });
    };
}

// 示例服务类
class ExampleService {
    sayHello() {
        return 'Hello from ExampleService';
    }
}

// 使用装饰器注入服务的目标类
class TargetClass {
    @Inject(ExampleService)
    exampleService: ExampleService;

    doSomething() {
        return this.exampleService.sayHello();
    }
}

优势

  1. 代码简洁:使用装饰器可以在目标类属性定义处直接声明依赖,代码更紧凑,可读性更高。例如在TargetClass中,通过@Inject(ExampleService)一行代码就完成了依赖注入,而传统方式可能需要更多的初始化代码。
  2. 解耦依赖关系:依赖注入的本质就是解耦,装饰器模式使得依赖关系在类的定义层面清晰呈现,便于理解和维护。修改依赖时,只需修改装饰器参数即可。
  3. 提高可测试性:在测试TargetClass时,可以通过模拟ExampleService并使用装饰器注入,轻松隔离测试TargetClass的业务逻辑,而不需要复杂的手动构建依赖对象。

劣势

  1. 性能开销:装饰器每次运行时都会执行注入逻辑,例如每次创建TargetClass实例时,都会重新创建ExampleService实例(如果未做单例处理),相较于传统方式提前创建好所有依赖并传入,可能存在一定性能损耗。
  2. 调试困难:由于装饰器是在编译阶段和运行阶段都有作用,当依赖注入出现问题时,例如注入失败或注入的对象不符合预期,调试相对复杂,因为错误可能出现在装饰器执行的各个阶段,且装饰器逻辑相对隐蔽,不如传统的构造函数注入等方式直观。
  3. 兼容性问题:TypeScript装饰器虽然强大,但并非所有JavaScript运行环境都原生支持,可能需要使用特定的转译工具或配置,在一些老旧项目或对兼容性要求较高的场景下使用受限。