第七节 工程化与高级特性-装饰器(Decorators)的应用场景
一、装饰器核心作用与启用
1. 本质与定位
- 元编程工具:在编译阶段动态修改类/方法/属性的行为(不改变源码)
- 启用配置:需在
tsconfig.json
中开启:{"compilerOptions": {"experimentalDecorators": true,"emitDecoratorMetadata": true // 支持反射元数据} }
2. 五大类型与参数
类型 | 作用目标 | 接收参数 |
---|---|---|
类装饰器 | 类构造函数 | target: Function (构造函数) |
方法装饰器 | 类方法 | target: any, propertyKey: string, descriptor: PropertyDescriptor |
属性装饰器 | 类属性 | target: any, propertyKey: string |
参数装饰器 | 方法参数 | target: any, propertyKey: string, parameterIndex: number |
访问器装饰器 | getter/setter | 同方法装饰器 |
二、工程化应用场景详解
1. 增强代码可维护性
-
日志跟踪:自动记录方法调用参数与耗时
function LogMethod(target: any, key: string, descriptor: PropertyDescriptor) {const original = descriptor.value;descriptor.value = function (...args: any[]) {console.log(`[${new Date()}] 调用方法 ${key},参数:`, args);return original.apply(this, args);}; }class UserService {@LogMethodgetUser(id: number) { /* 业务逻辑 */ } }
-
性能监控:统计关键方法执行时间
function MeasureTime(target: any, key: string, descriptor: PropertyDescriptor) {const original = descriptor.value;descriptor.value = function (...args: any[]) {const start = performance.now();const result = original.apply(this, args);console.log(`方法 ${key} 耗时: ${performance.now() - start}ms`);return result;}; }
2. 提升系统健壮性
-
数据验证:自动校验参数或属性合法性
function ValidateEmail(target: any, key: string) {let value = target[key];Object.defineProperty(target, key, {set: (newVal) => {if (!/^\S+@\S+\.\S+$/.test(newVal)) throw new Error("邮箱格式错误");value = newVal;}}); }class User {@ValidateEmailemail!: string; }
-
权限控制:拦截未授权操作
function Permission(role: string) {return (target: any, key: string, descriptor: PropertyDescriptor) => {const original = descriptor.value;descriptor.value = function (...args: any[]) {if (!currentUser.roles.includes(role)) throw new Error("权限不足");return original.apply(this, args);};}; }class AdminService {@Permission("ADMIN")deleteUser() { /* 敏感操作 */ } }
3. 框架级应用
-
依赖注入 (DI):自动实例化依赖对象(如 Angular/NestJS)
// 模拟 Angular 的 @Injectable function Injectable() {return (target: Function) => {// 注册到 DI 容器Container.register(target.name, new target());}; }@Injectable() class LoggerService {log(message: string) { console.log(message); } }
-
路由绑定:声明式 API 路由配置(如 Express 框架)
function Get(path: string) {return (target: any, key: string) => {Router.register("GET", path, target[key]);}; }class UserController {@Get("/users")getUsers() { /* 返回用户列表 */ } }
4. 设计模式实现
-
AOP(面向切面):分离业务逻辑与横切关注点
function Transactional(target: any, key: string, descriptor: PropertyDescriptor) {const original = descriptor.value;descriptor.value = async function (...args: any[]) {const tx = startTransaction(); // 开启事务try {const result = await original.apply(this, args);tx.commit(); // 提交事务return result;} catch (error) {tx.rollback(); // 回滚事务throw error;}}; }
-
装饰器工厂:动态生成定制化装饰器
function Cache(duration: number) {return (target: any, key: string, descriptor: PropertyDescriptor) => {const cache = new Map();const original = descriptor.value;descriptor.value = function (...args: any[]) {const cacheKey = JSON.stringify(args);if (cache.has(cacheKey)) return cache.get(cacheKey);const result = original.apply(this, args);cache.set(cacheKey, result);setTimeout(() => cache.delete(cacheKey), duration);return result;};}; }class WeatherService {@Cache(60000) // 缓存1分钟getForecast(city: string) { /* 调用API */ } }
三、开发实践建议
-
组合优于继承:
通过装饰器叠加功能(如日志+权限+缓存),避免深度继承链。 -
元数据反射:
结合reflect-metadata
库实现高级场景(如类型序列化)。 -
调试技巧:
- 使用
descriptor.value
保留原始方法引用 - 避免在装饰器内直接修改
target
原型(破坏封装性)
- 使用
-
框架选择:
框架 装饰器应用重点 Angular 依赖注入、组件生命周期挂钩 NestJS 控制器路由、中间件拦截器 TypeORM 实体字段映射、数据库关系定义
💡 总结:
装饰器通过 非侵入式增强 解决了代码重复问题(如日志/验证),在框架开发、AOP 编程、元数据管理等场景优势显著。需注意其仍为实验性特性,建议在严格类型约束下使用,避免过度抽象。