MST

星途 面试题库

面试题:TypeScript装饰器模式与元数据及依赖注入的结合

在一个大型项目中,使用TypeScript的装饰器模式结合元数据和依赖注入。假设有多个服务类,例如`UserService`、`OrderService`等,每个服务类有多个方法。要求通过装饰器给这些方法添加元数据(比如方法的访问权限、缓存策略等),并且利用依赖注入机制在运行时根据元数据动态配置服务。请阐述整体设计思路并给出关键代码示例。
20.0万 热度难度
前端开发TypeScript

知识考点

AI 面试

面试题答案

一键面试

整体设计思路

  1. 定义元数据装饰器:创建装饰器函数,用于给服务类的方法添加元数据,如访问权限、缓存策略等。
  2. 依赖注入容器:使用一个容器来管理服务类的实例化和依赖关系。
  3. 解析元数据并动态配置:在运行时,通过反射机制解析方法上的元数据,并根据元数据动态配置服务,如设置访问权限、应用缓存策略等。

关键代码示例

  1. 定义元数据装饰器
// 访问权限元数据装饰器
function AccessLevel(level: string) {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        Reflect.defineMetadata('accessLevel', level, target, propertyKey);
    };
}

// 缓存策略元数据装饰器
function CacheStrategy(strategy: string) {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        Reflect.defineMetadata('cacheStrategy', strategy, target, propertyKey);
    };
}
  1. 定义服务类
class UserService {
    @AccessLevel('admin')
    @CacheStrategy('none')
    getUser() {
        return 'User data';
    }
}

class OrderService {
    @AccessLevel('user')
    @CacheStrategy('short')
    getOrder() {
        return 'Order data';
    }
}
  1. 依赖注入容器
class Container {
    private services: { [key: string]: any } = {};

    register(name: string, service: any) {
        this.services[name] = service;
    }

    resolve(name: string): any {
        return this.services[name];
    }
}
  1. 解析元数据并动态配置服务
const container = new Container();
container.register('UserService', UserService);
container.register('OrderService', OrderService);

function configureServices() {
    const serviceNames = Object.keys(container.services);
    serviceNames.forEach(name => {
        const service = container.resolve(name);
        const prototype = Object.getPrototypeOf(service);
        const methodNames = Object.getOwnPropertyNames(prototype).filter(
            property => typeof prototype[property] === 'function' && property!== 'constructor'
        );
        methodNames.forEach(methodName => {
            const accessLevel = Reflect.getMetadata('accessLevel', prototype, methodName);
            const cacheStrategy = Reflect.getMetadata('cacheStrategy', prototype, methodName);
            console.log(`Service: ${name}, Method: ${methodName}, Access Level: ${accessLevel}, Cache Strategy: ${cacheStrategy}`);
            // 这里可以根据元数据进行动态配置,如访问控制、缓存逻辑等
        });
    });
}

configureServices();