第9章 装饰器:TypeScript的"元编程超能力"
想象你正在为超级英雄设计功能增强装甲——装饰器(Decorators) 就是TypeScript世界中的"钢铁侠战衣",它能在不改变原有代码结构的情况下,为类、方法和属性赋予全新的超能力!如果说前面章节教会了你构建代码的"身体",那么这一章将教你如何为代码穿上"智能装甲",让它们拥有监控、验证、缓存等各种神奇能力。
9.1 装饰器基础——理解"超能力装甲"的工作原理 ⚡
装饰器本质上是一个特殊的函数,就像为超级英雄量身定制的装甲一样,它能在不改变英雄本体的情况下,为其添加飞行、隐身、力量增强等各种能力。
🔧 装饰器配置:启动"实验室模式"
// 📁 tsconfig.json - 启用装饰器实验特性
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
console.log('装饰器实验室已启动');
// "装饰器实验室已启动"
🎯 最简单的装饰器:"基础监控装甲"
// 📁 basic-decorator.ts - 基础装饰器演示
/**
* 基础日志装饰器 - 为方法添加调用监控
* @param target 目标对象
* @param key 方法名
* @param descriptor 属性描述符
*/
function logDecorator(target: any, key: string, descriptor: PropertyDescriptor) {
console.log(`装饰器应用于方法: ${key}`);
console.log(`目标类: ${target.constructor.name}`);
console.log(`方法描述符:`, descriptor);
}
/**
* 增强版日志装饰器 - 监控方法调用过程
*/
function enhancedLog(target: any, key: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
console.log(`为 ${key} 方法安装监控装甲...`);
descriptor.value = function(...args: any[]) {
console.log(`🚀 调用方法: ${key}`);
console.log(`📥 输入参数:`, args);
const result = originalMethod.apply(this, args);
console.log(`📤 返回结果:`, result);
console.log(`✅ 方法 ${key} 执行完成`);
return result;
};
return descriptor;
}
class SuperHero {
constructor(public name: string) {
console.log(`超级英雄 ${name} 诞生!`);
}
@logDecorator
introduce() {
const message = `我是 ${this.name}!`;
console.log(message);
return message;
}
@enhancedLog
saveCity(cityName: string) {
const message = `${this.name} 拯救了 ${cityName}!`;
console.log(message);
return message;
}
}
console.log('=== 装饰器基础演示 ===');
// "=== 装饰器基础演示 ==="
// 装饰器在类定义时就会执行
// "装饰器应用于方法: introduce"
// "目标类: SuperHero"
// "方法描述符: {value: ƒ, writable: true, enumerable: false, configurable: true}"
// "为 saveCity 方法安装监控装甲..."
const hero = new SuperHero('钢铁侠');
// "超级英雄 钢铁侠 诞生!"
hero.introduce();
// "我是 钢铁侠!"
hero.saveCity('纽约');
// "🚀 调用方法: saveCity"
// "📥 输入参数: ['纽约']"
// "钢铁侠 拯救了 纽约!"
// "📤 返回结果: 钢铁侠 拯救了 纽约!"
// "✅ 方法 saveCity 执行完成"
⏰ 装饰器执行时机:"装甲安装顺序"
// 📁 execution-order.ts - 装饰器执行顺序演示
/**
* 类装饰器 - 为类添加防护能力
* @param name 装甲名称
*/
function classArmor(name: string) {
console.log(`🏭 ${name} 类装甲工厂启动`);
return function<T extends { new (...args: any[]): {} }>(constructor: T) {
console.log(`🔧 为类 ${constructor.name} 安装 ${name} 装甲`);
// 扩展类,添加防护属性和方法
return class extends constructor {
armor: string = name;
armorLevel: number = 50;
// 添加防护检查方法
checkArmor() {
console.log(`🛡️ ${name}装甲状态: ${this.armorLevel}%`);
return this.armorLevel > 0;
}
// 受到伤害时的防护计算
takeDamage(damage: number) {
const actualDamage = Math.max(0, damage - this.armorLevel * 0.5);
console.log(`🛡️ ${name}装甲减免伤害: ${damage} -> ${actualDamage}`);
return actualDamage;
}
};
};
}
/**
* 方法装饰器 - 为方法添加特殊能力
* @param name 装甲类型
*/
function methodArmor(name: string) {
console.log(`⚙️ ${name} 方法装甲工厂启动`);
return function(target: any, key: string, descriptor: PropertyDescriptor) {
console.log(`🔩 为方法 ${key} 安装 ${name} 装甲`);
const originalMethod = descriptor.value;
descriptor.value = function(...args: any[]) {
// 根据装甲类型添加不同的增强效果
if (name === '攻击') {
console.log(`⚔️ 激活${name}装甲: 攻击力提升50%!`);
const result = originalMethod.apply(this, args);
console.log(`💥 ${name}装甲效果: 造成额外伤害!`);
return result;
} else if (name === '防御') {
console.log(`🛡️ 激活${name}装甲: 防御力提升30%!`);
const result = originalMethod.apply(this, args);
console.log(`🔒 ${name}装甲效果: 减少受到的伤害!`);
return result;
} else {
return originalMethod.apply(this, args);
}
};
return descriptor;
};
}
/**
* 属性装饰器 - 为属性添加能量管理
* @param name 装甲名称
*/
function propertyArmor(name: string) {
console.log(`🛠️ ${name} 属性装甲工厂启动`);
return function(target: any, key: string) {
console.log(`🔗 为属性 ${key} 安装 ${name} 装甲`);
const privateKey = `_${key}`;
// 重新定义属性,添加能量管理逻辑
Object.defineProperty(target, key, {
get() {
return this[privateKey] || 0;
},
set(value: number) {
// 能量装甲提供能量恢复和保护
if (name === '能量') {
const maxEnergy = 150; // 能量装甲提升最大能量
const actualValue = Math.min(value, maxEnergy);
if (actualValue !== value) {
console.log(`⚡ ${name}装甲保护: 能量上限提升至${maxEnergy}`);
}
this[privateKey] = actualValue;
// 能量变化时的特殊效果
if (actualValue < 30) {
console.log(`⚠️ ${name}装甲警告: 能量不足,启动节能模式!`);
} else if (actualValue > 100) {
console.log(`✨ ${name}装甲增强: 能量充沛,性能提升!`);
}
} else {
this[privateKey] = value;
}
},
enumerable: true,
configurable: true
});
};
}
console.log('=== 装饰器执行顺序演示 ===');
// "=== 装饰器执行顺序演示 ===
@classArmor('防护')
class Robot {
@propertyArmor('能量')
energy: number = 100;
name: string;
health: number = 100;
constructor(name: string) {
this.name = name;
console.log(`🤖 机器人 ${name} 制造完成`);
}
@methodArmor('攻击')
@methodArmor('防御')
fight(enemy: string) {
console.log(`🤖 ${this.name} 向 ${enemy} 发起战斗!`);
// 消耗能量
this.energy -= 20;
console.log(`⚡ 战斗消耗能量,当前能量: ${this.energy}`);
return `${this.name} 对 ${enemy} 造成了强力攻击!`;
}
// 充能方法
recharge(amount: number) {
console.log(`🔋 ${this.name} 开始充能...`);
this.energy += amount;
console.log(`⚡ 充能完成,当前能量: ${this.energy}`);
}
// 状态检查
getStatus() {
const armor = (this as any).armor || '无';
const armorLevel = (this as any).armorLevel || 0;
console.log(`📊 ${this.name} 状态报告:`);
console.log(` 💚 生命值: ${this.health}`);
console.log(` ⚡ 能量: ${this.energy}`);
console.log(` 🛡️ 装甲: ${armor} (${armorLevel}%)`);
return {
name: this.name,
health: this.health,
energy: this.energy,
armor,
armorLevel
};
}
}
// 执行顺序输出:
// "🛠️ 能量 属性装甲工厂启动"
// "🔗 为属性 energy 安装 能量 装甲"
// "⚙️ 攻击 方法装甲工厂启动"
// "⚙️ 防御 方法装甲工厂启动"
// "🔩 为方法 fight 安装 防御 装甲"
// "🔩 为方法 fight 安装 攻击 装甲"
// "🏭 防护 类装甲工厂启动"
// "🔧 为类 Robot 安装 防护 装甲"
console.log('\n--- 机器人实战演示 ---');
// "--- 机器人实战演示 ---"
const robot = new Robot('战神一号');
// "🤖 机器人 战神一号 制造完成"
console.log('\n=== 初始状态检查 ===');
robot.getStatus();
// "📊 战神一号 状态报告:"
// " 💚 生命值: 100"
// " ⚡ 能量: 100"
// " 🛡️ 装甲: 防护 (50%)"
console.log('\n=== 装甲功能测试 ===');
(robot as any).checkArmor();
// "🛡️ 防护装甲状态: 50%"
const damage = (robot as any).takeDamage(60);
console.log(`实际受到伤害: ${damage}`);
// "🛡️ 防护装甲减免伤害: 60 -> 35"
// "实际受到伤害: 35"
console.log('\n=== 战斗测试 ===');
const battleResult = robot.fight('邪恶机器人');
// "🛡️ 激活防御装甲: 防御力提升30%!"
// "⚔️ 激活攻击装甲: 攻击力提升50%!"
// "🤖 战神一号 向 邪恶机器人 发起战斗!"
// "⚡ 战斗消耗能量,当前能量: 80"
// "💥 攻击装甲效果: 造成额外伤害!"
// "🔒 防御装甲效果: 减少受到的伤害!"
console.log(`战斗结果: ${battleResult}`);
// "战斗结果: 战神一号 对 邪恶机器人 造成了强力攻击!"
console.log('\n=== 能量管理测试 ===');
robot.energy = 25; // 触发低能量警告
// "⚠️ 能量装甲警告: 能量不足,启动节能模式!"
robot.recharge(50);
// "🔋 战神一号 开始充能..."
// "⚡ 充能完成,当前能量: 75"
robot.energy = 120; // 触发高能量增强
// "✨ 能量装甲增强: 能量充沛,性能提升!"
robot.energy = 200; // 测试能量上限保护
// "⚡ 能量装甲保护: 能量上限提升至150"
console.log('\n=== 最终状态 ===');
robot.getStatus();
// "📊 战神一号 状态报告:"
// " 💚 生命值: 100"
// " ⚡ 能量: 150"
// " 🛡️ 装甲: 防护 (50%)"
🎭 装饰器的神奇作用总结
在上面的机器人战甲系统中,我们可以清晰地看到装饰器在代码中发挥的五大核心作用:
1. 🔧 功能增强 - 无侵入式能力扩展
装饰器就像为机器人安装各种功能模块,不需要修改原有代码就能添加新功能:
-
classArmor
为整个类添加了防护系统(armor
、armorLevel
、checkArmor
、takeDamage
方法)
-
methodArmor
为战斗方法增加了攻击和防御增强效果
-
propertyArmor
为能量属性添加了智能管理和保护机制
2. 🎯 关注点分离 - 让代码职责更清晰
原始的 Robot
类只需要关心核心业务逻辑(战斗、充能、状态检查),而装甲系统、能量管理、增强效果等横切关注点都由装饰器独立处理,实现了完美的职责分离。
3. 🔄 代码复用 - 一次编写,处处使用
同一个装饰器可以应用到多个类或方法上:
// 同样的装甲系统可以用于不同的机器人
@classArmor('隐形')
class StealthRobot { /* ... */ }
@classArmor('飞行')
class FlyingRobot { /* ... */ }
4. 🎨 声明式编程 - 让意图更明确
通过装饰器,我们可以用声明式的方式表达代码意图:
-
@classArmor('防护')
一眼就能看出这个类具有防护能力
-
@methodArmor('攻击')
清楚表明这个方法具有攻击增强
-
@propertyArmor('能量')
明确显示这个属性有能量管理功能
5. 🔗 组合式设计 - 灵活的能力叠加
装饰器支持多重装饰,可以像搭积木一样组合不同的能力:
@methodArmor('攻击') // 先安装攻击装甲
@methodArmor('防御') // 再安装防御装甲
fight(enemy: string) { /* 现在同时具备攻防能力 */ }
💡 装饰器的设计哲学
装饰器体现了软件设计中的开闭原则(对扩展开放,对修改封闭):
- ✅ 开放扩展:可以随时添加新的装饰器来增强功能
- ✅ 封闭修改:不需要修改原有的类或方法代码
- ✅ 松耦合:装饰器与被装饰的代码相互独立
- ✅ 高内聚:每个装饰器专注于单一职责
通过这种方式,装饰器让我们的代码变得更加模块化、可维护、可扩展,真正实现了"给代码穿上智能装甲"的效果!
9.2 类装饰器——为整个类穿上"超级战甲" 🏛️
类装饰器是最强大的装饰器类型,它能完全改造一个类,就像为整栋建筑安装智能系统一样。
🔮 类装饰器的魔力:整体改造与增强
类装饰器应用于类的构造函数,可以监视、修改或替换类的定义。在实际开发中,类装饰器有这些典型应用场景:
1. 🏗️ 扩展类的功能
类装饰器可以为类添加新的属性、方法或行为:
-
addTimestamp
为类添加了创建时间追踪
-
addLogger
为类增加了日志记录能力
2. 🔒 控制实例化过程
类装饰器可以改变类的实例化行为:
-
singleton
确保类只有一个实例,实现单例模式
- 可以实现依赖注入、对象池等高级模式
3. 📊 添加元数据和监控
类装饰器可以为类添加元数据或监控能力:
- 记录类的使用情况和性能数据
- 为类添加版本信息、作者信息等元数据
4. 🔄 修改类的行为
类装饰器可以修改类的原有行为:
- 拦截方法调用
- 添加前置/后置处理逻辑
- 实现AOP(面向切面编程)
🕐 时间戳装甲:自动记录创建时间
// 📁 class-decorators.ts - 类装饰器演示
/**
* 时间戳装饰器 - 为类添加创建时间追踪
*/
function addTimestamp<T extends { new (...args: any[]): {} }>(constructor: T) {
console.log(`为类 ${constructor.name} 安装时间戳装甲`);
return class extends constructor {
createdAt = new Date();
constructor(...args: any[]) {
super(...args);
console.log(`${constructor.name} 实例创建于: ${this.createdAt.toISOString()}`);
}
getAge() {
const now = new Date();
const ageMs = now.getTime() - this.createdAt.getTime();
const ageSeconds = (ageMs / 1000).toFixed(2);
console.log(`实例存活时间: ${ageSeconds} 秒`);
return ageSeconds;
}
};
}
/**
* 单例装饰器 - 确保类只有一个实例
*/
function singleton<T extends { new (...args: any[]): {} }>(constructor: T) {
console.log(`为类 ${constructor.name} 安装单例装甲`);
let instance: any;
return class {
constructor(...args: any[]) {
if (!instance) {
console.log(`创建 ${constructor.name} 的唯一实例`);
instance = new constructor(...args);
} else {
console.log(`返回 ${constructor.name} 的现有实例`);
}
return instance;
}
} as T;
}
/**
* 日志装饰器 - 为类添加日志功能
*/
function addLogger<T extends { new (...args: any[]): {} }>(constructor: T) {
console.log(`为类 ${constructor.name} 安装日志装甲`);
return class extends constructor {
private logs: string[] = [];
log(message: string) {
const timestamp = new Date().toISOString();
const logEntry = `[${timestamp}] ${message}`;
this.logs.push(logEntry);
console.log(`📝 ${constructor.name}: ${logEntry}`);
}
getLogs() {
console.log(`获取 ${constructor.name} 的所有日志 (共${this.logs.length}条)`);
return [...this.logs];
}
clearLogs() {
const count = this.logs.length;
this.logs = [];
console.log(`清空 ${constructor.name} 的日志 (已清除${count}条)`);
}
};
}
console.log('=== 类装饰器演示 ===');
// "=== 类装饰器演示 ==="
@addTimestamp
@singleton
@addLogger
class DatabaseConnection {
constructor(public host: string, public port: number) {
console.log(`数据库连接初始化: ${host}:${port}`);
}
connect() {
const message = `连接到数据库 ${this.host}:${this.port}`;
console.log(message);
(this as any).log('数据库连接建立');
return message;
}
disconnect() {
const message = `断开数据库连接 ${this.host}:${this.port}`;
console.log(message);
(this as any).log('数据库连接断开');
return message;
}
}
// 装饰器安装过程:
// "为类 DatabaseConnection 安装日志装甲"
// "为类 DatabaseConnection 安装单例装甲"
// "为类 DatabaseConnection 安装时间戳装甲"
console.log('\n--- 测试单例模式 ---');
// "--- 测试单例模式 ---"
const db1 = new DatabaseConnection('localhost', 5432);
// "创建 DatabaseConnection 的唯一实例"
// "数据库连接初始化: localhost:5432"
// "DatabaseConnection 实例创建于: 2024-01-01T12:00:00.000Z"
const db2 = new DatabaseConnection('remote', 3306);
// "返回 DatabaseConnection 的现有实例"
console.log(`db1 === db2: ${db1 === db2}`);
// "db1 === db2: true"
console.log('\n--- 测试功能增强 ---');
// "--- 测试功能增强 ---"
db1.connect();
// "连接到数据库 localhost:5432"
// "📝 DatabaseConnection: [2024-01-01T12:00:00.100Z] 数据库连接建立"
// 等待一秒
setTimeout(() => {
(db1 as any).getAge();
// "实例存活时间: 1.00 秒"
db1.disconnect();
// "断开数据库连接 localhost:5432"
// "📝 DatabaseConnection: [2024-01-01T12:00:01.100Z] 数据库连接断开"
const logs = (db1 as any).getLogs();
// "获取 DatabaseConnection 的所有日志 (共2条)"
console.log('所有日志:', logs);
// "所有日志: ['[2024-01-01T12:00:00.100Z] 数据库连接建立', '[2024-01-01T12:00:01.100Z] 数据库连接断开']"
}, 1000);
🏭 配置工厂装甲:可定制的类增强
// 📁 configurable-class-decorators.ts - 可配置类装饰器
/**
* 缓存装饰器工厂 - 为类添加缓存功能
*/
function addCache(options: { maxSize?: number; ttl?: number } = {}) {
const { maxSize = 100, ttl = 60000 } = options; // 默认100个条目,60秒TTL
console.log(`创建缓存装甲工厂 (最大${maxSize}条目, TTL ${ttl}ms)`);
return function<T extends { new (...args: any[]): {} }>(constructor: T) {
console.log(`为类 ${constructor.name} 安装缓存装甲`);
return class extends constructor {
private cache = new Map<string, { value: any; timestamp: number }>();
setCache(key: string, value: any) {
// 清理过期缓存
this.cleanExpiredCache();
// 如果缓存已满,删除最旧的条目
if (this.cache.size >= maxSize) {
const firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
console.log(`缓存已满,删除最旧条目: ${firstKey}`);
}
this.cache.set(key, { value, timestamp: Date.now() });
console.log(`缓存设置: ${key} = ${JSON.stringify(value)}`);
}
getCache(key: string) {
const entry = this.cache.get(key);
if (!entry) {
console.log(`缓存未命中: ${key}`);
return null;
}
if (Date.now() - entry.timestamp > ttl) {
this.cache.delete(key);
console.log(`缓存过期: ${key}`);
return null;
}
console.log(`缓存命中: ${key} = ${JSON.stringify(entry.value)}`);
return entry.value;
}
private cleanExpiredCache() {
const now = Date.now();
let cleanedCount = 0;
for (const [key, entry] of this.cache.entries()) {
if (now - entry.timestamp > ttl) {
this.cache.delete(key);
cleanedCount++;
}
}
if (cleanedCount > 0) {
console.log(`清理过期缓存: ${cleanedCount} 条`);
}
}
getCacheStats() {
const stats = {
size: this.cache.size,
maxSize,
ttl,
keys: Array.from(this.cache.keys())
};
console.log('缓存统计:', stats);
return stats;
}
};
};
}
/**
* 性能监控装饰器工厂
*/
function addPerformanceMonitor(options: { logThreshold?: number } = {}) {
const { logThreshold = 100 } = options; // 默认100ms阈值
console.log(`创建性能监控装甲工厂 (阈值 ${logThreshold}ms)`);
return function<T extends { new (...args: any[]): {} }>(constructor: T) {
console.log(`为类 ${constructor.name} 安装性能监控装甲`);
return class extends constructor {
private performanceData: { [method: string]: number[] } = {};
recordPerformance(methodName: string, duration: number) {
if (!this.performanceData[methodName]) {
this.performanceData[methodName] = [];
}
this.performanceData[methodName].push(duration);
if (duration > logThreshold) {
console.log(`⚠️ 性能警告: ${methodName} 耗时 ${duration.toFixed(2)}ms (超过阈值 ${logThreshold}ms)`);
} else {
console.log(`✅ 性能正常: ${methodName} 耗时 ${duration.toFixed(2)}ms`);
}
}
getPerformanceReport() {
const report: any = {};
for (const [method, durations] of Object.entries(this.performanceData)) {
const avg = durations.reduce((a, b) => a + b, 0) / durations.length;
const min = Math.min(...durations);
const max = Math.max(...durations);
report[method] = {
calls: durations.length,
average: Number(avg.toFixed(2)),
min: Number(min.toFixed(2)),
max: Number(max.toFixed(2))
};
}
console.log('性能报告:', report);
return report;
}
};
};
}
console.log('=== 可配置类装饰器演示 ===');
// "=== 可配置类装饰器演示 ==="
@addCache({ maxSize: 5, ttl: 3000 })
@addPerformanceMonitor({ logThreshold: 50 })
class DataProcessor {
constructor(public name: string) {
console.log(`数据处理器 ${name} 初始化`);
}
processData(data: any) {
const start = performance.now();
// 模拟数据处理
const processed = { ...data, processed: true, timestamp: Date.now() };
// 模拟处理时间
const delay = Math.random() * 100;
const syncEnd = Date.now() + delay;
while (Date.now() < syncEnd) {}
const duration = performance.now() - start;
(this as any).recordPerformance('processData', duration);
console.log(`处理数据:`, processed);
return processed;
}
}
// 装饰器安装过程:
// "创建缓存装甲工厂 (最大5条目, TTL 3000ms)"
// "创建性能监控装甲工厂 (阈值 50ms)"
// "为类 DataProcessor 安装性能监控装甲"
// "为类 DataProcessor 安装缓存装甲"
const processor = new DataProcessor('主处理器');
// "数据处理器 主处理器 初始化"
console.log('\n--- 测试数据处理和性能监控 ---');
// "--- 测试数据处理和性能监控 ---"
// 处理多个数据
for (let i = 1; i <= 3; i++) {
const data = { id: i, value: `数据${i}` };
const result = processor.processData(data);
// 设置缓存
(processor as any).setCache(`data_${i}`, result);
}
// 可能的输出:
// "✅ 性能正常: processData 耗时 25.30ms"
// "处理数据: {id: 1, value: '数据1', processed: true, timestamp: 1704067200000}"
// "缓存设置: data_1 = {\"id\":1,\"value\":\"数据1\",\"processed\":true,\"timestamp\":1704067200000}"
// "⚠️ 性能警告: processData 耗时 75.20ms (超过阈值 50ms)"
// "处理数据: {id: 2, value: '数据2', processed: true, timestamp: 1704067200100}"
// "缓存设置: data_2 = {\"id\":2,\"value\":\"数据2\",\"processed\":true,\"timestamp\":1704067200100}"
setTimeout(() => {
console.log('\n--- 测试缓存功能 ---');
// "--- 测试缓存功能 ---"
(processor as any).getCache('data_1');
// "缓存命中: data_1 = {\"id\":1,\"value\":\"数据1\",\"processed\":true,\"timestamp\":1704067200000}"
(processor as any).getCacheStats();
// "缓存统计: {size: 3, maxSize: 5, ttl: 3000, keys: ['data_1', 'data_2', 'data_3']}"
(processor as any).getPerformanceReport();
// "性能报告: {processData: {calls: 3, average: 45.67, min: 25.30, max: 75.20}}"
}, 1000);
9.3 方法装饰器——为方法装上"智能监控系统" ⚡
方法装饰器就像为每个方法安装了智能监控系统,能够拦截、分析和增强方法的执行过程。
🎯 方法装饰器的核心价值:精准的方法增强
方法装饰器是最常用的装饰器类型,它们专注于方法级别的功能增强,在实际开发中有着广泛的应用:
1. 📊 性能监控与分析
-
measureTime
监控方法执行时间,帮助识别性能瓶颈
- 记录方法调用频率和执行统计
- 实现性能预警和优化建议
2. 🔄 错误处理与重试
-
retry
为不稳定的方法提供自动重试机制
- 实现指数退避、熔断器等高级错误处理策略
- 提供优雅的失败降级处理
3. 💾 缓存与优化
-
cache
为计算密集型方法提供结果缓存
- 实现智能缓存策略(LRU、TTL等)
- 减少重复计算,提升应用性能
4. 🔍 参数验证与安全
-
validateArgs
确保方法参数的合法性
- 实现输入过滤、类型检查、权限验证
- 提供统一的参数校验机制
5. 📝 日志与调试
- 自动记录方法调用日志
- 追踪方法执行流程和状态变化
- 提供调试信息和审计跟踪
🕐 执行时间监控:"性能分析仪"
// 📁 method-decorators.ts - 方法装饰器演示
/**
* 执行时间测量装饰器
*/
function measureTime(target: any, key: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
console.log(`为方法 ${key} 安装性能监控装甲`);
descriptor.value = function(...args: any[]) {
console.log(`⏱️ 开始执行 ${key}`);
const start = performance.now();
const result = originalMethod.apply(this, args);
const end = performance.now();
const duration = (end - start).toFixed(2);
console.log(`⏱️ ${key} 执行耗时: ${duration}ms`);
return result;
};
return descriptor;
}
/**
* 自动重试装饰器工厂
*/
function retry(times: number, delay: number = 100) {
console.log(`创建重试装甲工厂 (最多${times}次, 延迟${delay}ms)`);
return function(target: any, key: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
console.log(`为方法 ${key} 安装重试装甲`);
descriptor.value = async function(...args: any[]) {
for (let attempt = 1; attempt <= times; attempt++) {
try {
console.log(`🔄 ${key} 第${attempt}次尝试`);
const result = await originalMethod.apply(this, args);
if (attempt > 1) {
console.log(`✅ ${key} 在第${attempt}次尝试成功`);
}
return result;
} catch (error) {
console.log(`❌ ${key} 第${attempt}次尝试失败:`, (error as Error).message);
if (attempt === times) {
console.log(`💥 ${key} 所有重试都失败了`);
throw error;
}
console.log(`⏳ 等待 ${delay}ms 后重试...`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
};
return descriptor;
};
}
/**
* 缓存装饰器工厂
*/
function cache(ttl: number = 60000) {
console.log(`创建缓存装甲工厂 (TTL ${ttl}ms)`);
return function(target: any, key: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
const cacheMap = new Map<string, { value: any; timestamp: number }>();
console.log(`为方法 ${key} 安装缓存装甲`);
descriptor.value = function(...args: any[]) {
const cacheKey = JSON.stringify(args);
const now = Date.now();
// 检查缓存
const cached = cacheMap.get(cacheKey);
if (cached && (now - cached.timestamp) < ttl) {
console.log(`💾 ${key} 缓存命中:`, cacheKey);
return cached.value;
}
console.log(`🔍 ${key} 缓存未命中,执行方法`);
const result = originalMethod.apply(this, args);
// 存储到缓存
cacheMap.set(cacheKey, { value: result, timestamp: now });
console.log(`💾 ${key} 结果已缓存:`, cacheKey);
return result;
};
return descriptor;
};
}
/**
* 参数验证装饰器工厂
*/
function validateArgs(validators: ((arg: any) => boolean)[]) {
console.log(`创建参数验证装甲工厂 (${validators.length}个验证器)`);
return function(target: any, key: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
console.log(`为方法 ${key} 安装参数验证装甲`);
descriptor.value = function(...args: any[]) {
console.log(`🔍 验证 ${key} 的参数:`, args);
for (let i = 0; i < validators.length && i < args.length; i++) {
const isValid = validators[i](args[i]);
console.log(`📋 参数${i} 验证: ${isValid ? '✅ 通过' : '❌ 失败'}`);
if (!isValid) {
const error = new Error(`${key} 的参数${i} 验证失败: ${args[i]}`);
console.log(`💥 ${error.message}`);
throw error;
}
}
console.log(`✅ ${key} 所有参数验证通过`);
return originalMethod.apply(this, args);
};
return descriptor;
};
}
console.log('=== 方法装饰器演示 ===');
// "=== 方法装饰器演示 ==="
class ApiService {
constructor(public baseUrl: string) {
console.log(`API服务初始化: ${baseUrl}`);
}
@measureTime
@cache(5000) // 5秒缓存
@validateArgs([
(url: string) => typeof url === 'string' && url.length > 0,
(options: any) => !options || typeof options === 'object'
])
async fetchData(url: string, options?: any) {
console.log(`🌐 发起请求: ${this.baseUrl}${url}`);
// 模拟网络请求
const delay = Math.random() * 1000 + 500; // 500-1500ms
await new Promise(resolve => setTimeout(resolve, delay));
// 模拟随机失败
if (Math.random() < 0.3) {
throw new Error('网络请求失败');
}
const data = {
url: `${this.baseUrl}${url}`,
timestamp: Date.now(),
data: `模拟数据 for ${url}`
};
console.log(`📦 请求成功:`, data);
return data;
}
@measureTime
@retry(3, 500)
async uploadFile(file: string, size: number) {
console.log(`📤 上传文件: ${file} (${size} bytes)`);
// 模拟上传过程
const delay = size / 1000; // 根据文件大小模拟上传时间
await new Promise(resolve => setTimeout(resolve, delay));
// 模拟上传失败概率
if (Math.random() < 0.6) {
throw new Error('上传失败');
}
const result = {
file,
size,
uploadedAt: new Date().toISOString(),
fileId: Math.random().toString(36).substr(2, 9)
};
console.log(`✅ 文件上传成功:`, result);
return result;
}
@measureTime
processResponse(data: any) {
console.log(`🔄 处理响应数据`);
// 模拟数据处理
const processed = {
...data,
processed: true,
processedAt: Date.now()
};
console.log(`✅ 数据处理完成:`, processed);
return processed;
}
}
// 装饰器安装过程:
// "创建参数验证装甲工厂 (2个验证器)"
// "创建缓存装甲工厂 (TTL 5000ms)"
// "为方法 fetchData 安装参数验证装甲"
// "为方法 fetchData 安装缓存装甲"
// "为方法 fetchData 安装性能监控装甲"
// "创建重试装甲工厂 (最多3次, 延迟500ms)"
// "为方法 uploadFile 安装重试装甲"
// "为方法 uploadFile 安装性能监控装甲"
// "为方法 processResponse 安装性能监控装甲"
const api = new ApiService('https://api.example.com');
// "API服务初始化: https://api.example.com"
console.log('\n--- 测试数据获取 ---');
// "--- 测试数据获取 ---"
// 测试正常请求
api.fetchData('/users', { page: 1 }).then(data => {
console.log('第一次请求完成');
// 测试缓存
return api.fetchData('/users', { page: 1 });
}).then(data => {
console.log('第二次请求完成 (应该命中缓存)');
}).catch(error => {
console.log('请求失败:', error.message);
});
// 可能的输出:
// "🔍 验证 fetchData 的参数: ['/users', {page: 1}]"
// "📋 参数0 验证: ✅ 通过"
// "📋 参数1 验证: ✅ 通过"
// "✅ fetchData 所有参数验证通过"
// "🔍 fetchData 缓存未命中,执行方法"
// "⏱️ 开始执行 fetchData"
// "🌐 发起请求: https://api.example.com/users"
// "📦 请求成功: {url: 'https://api.example.com/users', timestamp: 1704067200000, data: '模拟数据 for /users'}"
// "💾 fetchData 结果已缓存: [\"/users\",{\"page\":1}]"
// "⏱️ fetchData 执行耗时: 750.25ms"
// "第一次请求完成"
// "🔍 验证 fetchData 的参数: ['/users', {page: 1}]"
// "📋 参数0 验证: ✅ 通过"
// "📋 参数1 验证: ✅ 通过"
// "✅ fetchData 所有参数验证通过"
// "💾 fetchData 缓存命中: [\"/users\",{\"page\":1}]"
// "第二次请求完成 (应该命中缓存)"
console.log('\n--- 测试文件上传 ---');
// "--- 测试文件上传 ---"
api.uploadFile('document.pdf', 1024000).then(result => {
console.log('文件上传成功:', result);
}).catch(error => {
console.log('文件上传最终失败:', error.message);
});
// 可能的输出:
// "⏱️ 开始执行 uploadFile"
// "🔄 uploadFile 第1次尝试"
// "📤 上传文件: document.pdf (1024000 bytes)"
// "❌ uploadFile 第1次尝试失败: 上传失败"
// "⏳ 等待 500ms 后重试..."
// "🔄 uploadFile 第2次尝试"
// "📤 上传文件: document.pdf (1024000 bytes)"
// "✅ 文件上传成功: {file: 'document.pdf', size: 1024000, uploadedAt: '2024-01-01T12:00:01.000Z', fileId: 'abc123def'}"
// "✅ uploadFile 在第2次尝试成功"
// "⏱️ uploadFile 执行耗时: 1524.50ms"
// "文件上传成功: {file: 'document.pdf', size: 1024000, uploadedAt: '2024-01-01T12:00:01.000Z', fileId: 'abc123def'}"
// 测试参数验证失败
setTimeout(() => {
console.log('\n--- 测试参数验证 ---');
// "--- 测试参数验证 ---"
api.fetchData('', null).catch(error => {
console.log('参数验证失败:', error.message);
});
// 输出:
// "🔍 验证 fetchData 的参数: ['', null]"
// "📋 参数0 验证: ❌ 失败"
// "💥 fetchData 的参数0 验证失败: "
// "参数验证失败: fetchData 的参数0 验证失败: "
}, 2000);
🔄 异步方法增强:"智能异步管理器"
// 📁 async-method-decorators.ts - 异步方法装饰器
/**
* 防抖装饰器工厂 - 防止方法被频繁调用
*/
function debounce(delay: number) {
console.log(`创建防抖装甲工厂 (延迟 ${delay}ms)`);
return function(target: any, key: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
let timeoutId: NodeJS.Timeout | number;
console.log(`为方法 ${key} 安装防抖装甲`);
descriptor.value = function(...args: any[]) {
console.log(`🔄 ${key} 防抖触发`);
clearTimeout(timeoutId);
return new Promise((resolve, reject) => {
timeoutId = setTimeout(async () => {
try {
console.log(`⚡ ${key} 防抖延迟结束,执行方法`);
const result = await originalMethod.apply(this, args);
resolve(result);
} catch (error) {
reject(error);
}
}, delay);
});
};
return descriptor;
};
}
/**
* 节流装饰器工厂 - 限制方法调用频率
*/
function throttle(interval: number) {
console.log(`创建节流装甲工厂 (间隔 ${interval}ms)`);
return function(target: any, key: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
let lastCallTime = 0;
let isThrottled = false;
console.log(`为方法 ${key} 安装节流装甲`);
descriptor.value = async function(...args: any[]) {
const now = Date.now();
if (isThrottled) {
console.log(`🚫 ${key} 被节流限制,忽略调用`);
return;
}
if (now - lastCallTime < interval) {
console.log(`⏳ ${key} 调用过于频繁,等待节流间隔`);
isThrottled = true;
setTimeout(() => {
isThrottled = false;
console.log(`✅ ${key} 节流解除`);
}, interval - (now - lastCallTime));
return;
}
console.log(`⚡ ${key} 节流检查通过,执行方法`);
lastCallTime = now;
return await originalMethod.apply(this, args);
};
return descriptor;
};
}
/**
* 超时装饰器工厂 - 为异步方法添加超时控制
*/
function timeout(ms: number) {
console.log(`创建超时装甲工厂 (超时 ${ms}ms)`);
return function(target: any, key: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
console.log(`为方法 ${key} 安装超时装甲`);
descriptor.value = async function(...args: any[]) {
console.log(`⏰ ${key} 开始执行,设置 ${ms}ms 超时`);
return Promise.race([
originalMethod.apply(this, args),
new Promise((_, reject) => {
setTimeout(() => {
console.log(`⏰ ${key} 执行超时 (${ms}ms)`);
reject(new Error(`${key} 执行超时`));
}, ms);
})
]);
};
return descriptor;
};
}
/**
* 并发控制装饰器工厂 - 限制同时执行的实例数
*/
function concurrent(maxConcurrent: number) {
console.log(`创建并发控制装甲工厂 (最大并发 ${maxConcurrent})`);
return function(target: any, key: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
let runningCount = 0;
const queue: Array<{ resolve: Function; reject: Function; args: any[] }> = [];
console.log(`为方法 ${key} 安装并发控制装甲`);
descriptor.value = async function(...args: any[]) {
return new Promise((resolve, reject) => {
const execute = async () => {
if (runningCount >= maxConcurrent) {
console.log(`🚦 ${key} 并发已满 (${runningCount}/${maxConcurrent}),加入队列`);
queue.push({ resolve, reject, args });
return;
}
runningCount++;
console.log(`🚀 ${key} 开始执行 (当前并发: ${runningCount}/${maxConcurrent})`);
try {
const result = await originalMethod.apply(this, args);
resolve(result);
} catch (error) {
reject(error);
} finally {
runningCount--;
console.log(`✅ ${key} 执行完成 (当前并发: ${runningCount}/${maxConcurrent})`);
// 处理队列中的下一个任务
if (queue.length > 0) {
const next = queue.shift()!;
console.log(`📋 ${key} 从队列中取出下一个任务`);
setImmediate(() => {
execute.call(this).then(next.resolve).catch(next.reject);
});
}
}
};
execute.call(this);
});
};
return descriptor;
};
}
console.log('=== 异步方法装饰器演示 ===');
// "=== 异步方法装饰器演示 ==="
class SearchService {
constructor(public name: string) {
console.log(`搜索服务 ${name} 初始化`);
}
@debounce(300)
async searchUsers(query: string) {
console.log(`🔍 搜索用户: "${query}"`);
// 模拟搜索延迟
await new Promise(resolve => setTimeout(resolve, 200));
const results = [
{ id: 1, name: `用户1_${query}`, email: `user1_${query}@example.com` },
{ id: 2, name: `用户2_${query}`, email: `user2_${query}@example.com` }
];
console.log(`📋 搜索结果:`, results);
return results;
}
@throttle(1000)
async sendNotification(message: string) {
console.log(`📢 发送通知: "${message}"`);
// 模拟发送延迟
await new Promise(resolve => setTimeout(resolve, 100));
const result = {
message,
sentAt: new Date().toISOString(),
id: Math.random().toString(36).substr(2, 9)
};
console.log(`✅ 通知发送成功:`, result);
return result;
}
@timeout(2000)
async fetchExternalData(url: string) {
console.log(`🌐 获取外部数据: ${url}`);
// 模拟随机延迟
const delay = Math.random() * 3000; // 0-3秒
await new Promise(resolve => setTimeout(resolve, delay));
const data = {
url,
data: `外部数据 from ${url}`,
fetchedAt: Date.now()
};
console.log(`📦 外部数据获取成功:`, data);
return data;
}
@concurrent(2)
async processLargeFile(filename: string, size: number) {
console.log(`📁 处理大文件: ${filename} (${size} MB)`);
// 模拟文件处理时间(基于文件大小)
const processingTime = size * 100; // 每MB需要100ms
await new Promise(resolve => setTimeout(resolve, processingTime));
const result = {
filename,
size,
processedAt: new Date().toISOString(),
outputPath: `/processed/${filename}`
};
console.log(`✅ 文件处理完成:`, result);
return result;
}
}
// 装饰器安装过程:
// "创建防抖装甲工厂 (延迟 300ms)"
// "为方法 searchUsers 安装防抖装甲"
// "创建节流装甲工厂 (间隔 1000ms)"
// "为方法 sendNotification 安装节流装甲"
// "创建超时装甲工厂 (超时 2000ms)"
// "为方法 fetchExternalData 安装超时装甲"
// "创建并发控制装甲工厂 (最大并发 2)"
// "为方法 processLargeFile 安装并发控制装甲"
const searchService = new SearchService('主搜索服务');
// "搜索服务 主搜索服务 初始化"
console.log('\n--- 测试防抖搜索 ---');
// "--- 测试防抖搜索 ---"
// 快速连续搜索(只有最后一次会执行)
searchService.searchUsers('张');
// "🔄 searchUsers 防抖触发"
searchService.searchUsers('张三');
// "🔄 searchUsers 防抖触发"
searchService.searchUsers('张三丰').then(results => {
console.log('防抖搜索完成:', results.length, '个结果');
});
// "🔄 searchUsers 防抖触发"
// (300ms后)
// "⚡ searchUsers 防抖延迟结束,执行方法"
// "🔍 搜索用户: \"张三丰\""
// "📋 搜索结果: [{id: 1, name: '用户1_张三丰', email: 'user1_张三丰@example.com'}, {id: 2, name: '用户2_张三丰', email: 'user2_张三丰@example.com'}]"
// "防抖搜索完成: 2 个结果"
console.log('\n--- 测试节流通知 ---');
// "--- 测试节流通知 ---"
// 快速连续发送通知(会被节流限制)
searchService.sendNotification('消息1');
// "⚡ sendNotification 节流检查通过,执行方法"
// "📢 发送通知: \"消息1\""
// "✅ 通知发送成功: {message: '消息1', sentAt: '2024-01-01T12:00:00.000Z', id: 'abc123def'}"
searchService.sendNotification('消息2');
// "⏳ sendNotification 调用过于频繁,等待节流间隔"
searchService.sendNotification('消息3');
// "🚫 sendNotification 被节流限制,忽略调用"
console.log('\n--- 测试超时控制 ---');
// "--- 测试超时控制 ---"
// 测试正常请求
searchService.fetchExternalData('https://api.fast.com/data').then(data => {
console.log('快速请求成功:', data.url);
}).catch(error => {
console.log('快速请求失败:', error.message);
});
// 测试超时请求
searchService.fetchExternalData('https://api.slow.com/data').then(data => {
console.log('慢速请求成功:', data.url);
}).catch(error => {
console.log('慢速请求失败:', error.message);
});
// 可能的输出:
// "⏰ fetchExternalData 开始执行,设置 2000ms 超时"
// "🌐 获取外部数据: https://api.fast.com/data"
// "⏰ fetchExternalData 开始执行,设置 2000ms 超时"
// "🌐 获取外部数据: https://api.slow.com/data"
// "📦 外部数据获取成功: {url: 'https://api.fast.com/data', data: '外部数据 from https://api.fast.com/data', fetchedAt: 1704067200000}"
// "快速请求成功: https://api.fast.com/data"
// "⏰ fetchExternalData 执行超时 (2000ms)"
// "慢速请求失败: fetchExternalData 执行超时"
console.log('\n--- 测试并发控制 ---');
// "--- 测试并发控制 ---"
// 同时处理多个大文件(最多2个并发)
const files = [
{ name: 'video1.mp4', size: 5 },
{ name: 'video2.mp4', size: 3 },
{ name: 'video3.mp4', size: 4 },
{ name: 'video4.mp4', size: 2 }
];
files.forEach((file, index) => {
searchService.processLargeFile(file.name, file.size).then(result => {
console.log(`文件 ${index + 1} 处理完成:`, result.filename);
});
});
// 可能的输出:
// "🚀 processLargeFile 开始执行 (当前并发: 1/2)"
// "📁 处理大文件: video1.mp4 (5 MB)"
// "🚀 processLargeFile 开始执行 (当前并发: 2/2)"
// "📁 处理大文件: video2.mp4 (3 MB)"
// "🚦 processLargeFile 并发已满 (2/2),加入队列"
// "🚦 processLargeFile 并发已满 (2/2),加入队列"
// "✅ 文件处理完成: {filename: 'video2.mp4', size: 3, processedAt: '2024-01-01T12:00:00.300Z', outputPath: '/processed/video2.mp4'}"
// "文件 2 处理完成: video2.mp4"
// "✅ processLargeFile 执行完成 (当前并发: 1/2)"
// "📋 processLargeFile 从队列中取出下一个任务"
// "🚀 processLargeFile 开始执行 (当前并发: 2/2)"
// "📁 处理大文件: video3.mp4 (4 MB)"
9.4 属性装饰器——为属性装上"智能管家系统" 🔒
属性装饰器就像为每个属性配备了专业的管家,能够监控访问、验证数据、自动转换格式等。
🏠 属性装饰器的管家职责:精细化属性管理
属性装饰器专注于属性级别的控制和增强,它们像贴身管家一样,为每个属性提供个性化的服务:
1. 🔐 访问控制与权限管理
-
readonly
创建只读属性,防止意外修改
- 实现属性级别的权限控制
- 提供细粒度的访问策略
2. ✅ 数据验证与完整性保护
-
validate
确保属性值符合业务规则
- 实时验证数据格式、范围、类型
- 提供友好的错误提示和处理
3. 🔄 自动转换与格式化
-
transform
自动转换属性值格式
- 实现数据的标准化和规范化
- 支持复杂的数据转换逻辑
4. 📊 监控与审计
- 记录属性的读写操作
- 追踪属性值的变化历史
- 提供属性使用统计和分析
5. 🎯 业务逻辑集成
- 在属性变化时触发业务逻辑
- 实现属性间的联动和依赖
- 支持复杂的业务规则验证
🔐 访问控制:"权限管理系统"
// 📁 property-decorators.ts - 属性装饰器演示
/**
* 只读装饰器工厂 - 创建只读属性
*/
function readonly(writable: boolean = false) {
console.log(`创建只读装甲工厂 (可写: ${writable})`);
return function(target: any, key: string) {
console.log(`为属性 ${key} 安装只读装甲`);
const privateKey = `_${key}`;
Object.defineProperty(target, key, {
get: function() {
const value = this[privateKey];
console.log(`🔍 读取属性 ${key}: ${JSON.stringify(value)}`);
return value;
},
set: function(value) {
if (!writable && this[privateKey] !== undefined) {
const error = new Error(`属性 ${key} 是只读的`);
console.log(`🚫 ${error.message}`);
throw error;
}
console.log(`✏️ 设置属性 ${key}: ${JSON.stringify(value)}`);
this[privateKey] = value;
},
enumerable: true,
configurable: true
});
};
}
/**
* 格式验证装饰器工厂
*/
function validate(validator: (value: any) => boolean, errorMessage?: string) {
console.log(`创建验证装甲工厂`);
return function(target: any, key: string) {
console.log(`为属性 ${key} 安装验证装甲`);
const privateKey = `_${key}`;
Object.defineProperty(target, key, {
get: function() {
const value = this[privateKey];
console.log(`🔍 读取已验证属性 ${key}: ${JSON.stringify(value)}`);
return value;
},
set: function(value) {
console.log(`🔍 验证属性 ${key} 的值: ${JSON.stringify(value)}`);
const isValid = validator(value);
console.log(`📋 验证结果: ${isValid ? '✅ 通过' : '❌ 失败'}`);
if (!isValid) {
const error = new Error(errorMessage || `属性 ${key} 验证失败: ${value}`);
console.log(`💥 ${error.message}`);
throw error;
}
console.log(`✅ 属性 ${key} 验证通过,设置值`);
this[privateKey] = value;
},
enumerable: true,
configurable: true
});
};
}
/**
* 自动转换装饰器工厂
*/
function transform(transformer: (value: any) => any) {
console.log(`创建转换装甲工厂`);
return function(target: any, key: string) {
console.log(`为属性 ${key} 安装转换装甲`);
const privateKey = `_${key}`;
Object.defineProperty(target, key, {
get: function() {
const value = this[privateKey];
console.log(`🔍 读取转换属性 ${key}: ${JSON.stringify(value)}`);
return value;
},
set: function(value) {
console.log(`🔄 转换属性 ${key} 的值: ${JSON.stringify(value)}`);
const transformedValue = transformer(value);
console.log(`✨ 转换结果: ${JSON.stringify(transformedValue)}`);
this[privateKey] = transformedValue;
},
enumerable: true,
configurable: true
});
};
}
console.log('=== 属性装饰器演示 ===');
// "=== 属性装饰器演示 ==="
class UserProfile {
@readonly(false)
id: string;
@validate(
(value: string) => typeof value === 'string' && value.length >= 2,
'用户名至少需要2个字符'
)
username: string;
@validate(
(value: string) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value),
'邮箱格式不正确'
)
email: string;
@transform((value: string) => value.toLowerCase().trim())
@validate(
(value: string) => ['admin', 'user', 'guest'].includes(value),
'角色必须是 admin、user 或 guest'
)
role: string;
@transform((value: number) => Math.max(0, Math.min(120, value)))
@validate(
(value: number) => typeof value === 'number' && value >= 0 && value <= 120,
'年龄必须在0-120之间'
)
age: number;
constructor(id: string) {
console.log(`创建用户档案: ${id}`);
this.id = id;
}
getInfo() {
return {
id: this.id,
username: this.username,
email: this.email,
role: this.role,
age: this.age
};
}
}
// 装饰器安装过程:
// "创建只读装甲工厂 (可写: false)"
// "为属性 id 安装只读装甲"
// "创建验证装甲工厂"
// "为属性 username 安装验证装甲"
// "创建验证装甲工厂"
// "为属性 email 安装验证装甲"
// "创建转换装甲工厂"
// "创建验证装甲工厂"
// "为属性 role 安装验证装甲"
// "为属性 role 安装转换装甲"
// "创建转换装甲工厂"
// "创建验证装甲工厂"
// "为属性 age 安装验证装甲"
// "为属性 age 安装转换装甲"
const user = new UserProfile('user_001');
// "创建用户档案: user_001"
// "✏️ 设置属性 id: \"user_001\""
console.log('\n--- 测试属性设置和验证 ---');
// "--- 测试属性设置和验证 ---"
// 设置有效的用户名
user.username = '张三';
// "🔍 验证属性 username 的值: \"张三\""
// "📋 验证结果: ✅ 通过"
// "✅ 属性 username 验证通过,设置值"
// 设置有效的邮箱
user.email = 'zhangsan@example.com';
// "🔍 验证属性 email 的值: \"zhangsan@example.com\""
// "📋 验证结果: ✅ 通过"
// "✅ 属性 email 验证通过,设置值"
// 设置角色(会自动转换为小写)
user.role = ' ADMIN ';
// "🔄 转换属性 role 的值: \" ADMIN \""
// "✨ 转换结果: \"admin\""
// "🔍 验证属性 role 的值: \"admin\""
// "📋 验证结果: ✅ 通过"
// "✅ 属性 role 验证通过,设置值"
// 设置年龄(会自动限制在合理范围内)
user.age = 150;
// "🔄 转换属性 age 的值: 150"
// "✨ 转换结果: 120"
// "🔍 验证属性 age 的值: 120"
// "📋 验证结果: ✅ 通过"
// "✅ 属性 age 验证通过,设置值"
console.log('\n--- 测试属性读取 ---');
// "--- 测试属性读取 ---"
const info = user.getInfo();
// "🔍 读取属性 id: \"user_001\""
// "🔍 读取已验证属性 username: \"张三\""
// "🔍 读取已验证属性 email: \"zhangsan@example.com\""
// "🔍 读取转换属性 role: \"admin\""
// "🔍 读取转换属性 age: 120"
console.log('用户信息:', info);
// "用户信息: {id: 'user_001', username: '张三', email: 'zhangsan@example.com', role: 'admin', age: 120}"
console.log('\n--- 测试验证失败 ---');
// "--- 测试验证失败 ---"
// 测试用户名验证失败
try {
user.username = 'a';
} catch (error) {
console.log('用户名验证失败:', (error as Error).message);
}
// "🔍 验证属性 username 的值: \"a\""
// "📋 验证结果: ❌ 失败"
// "💥 用户名至少需要2个字符"
// "用户名验证失败: 用户名至少需要2个字符"
// 测试邮箱验证失败
try {
user.email = '无效邮箱';
} catch (error) {
console.log('邮箱验证失败:', (error as Error).message);
}
// "🔍 验证属性 email 的值: \"无效邮箱\""
// "📋 验证结果: ❌ 失败"
// "💥 邮箱格式不正确"
// "邮箱验证失败: 邮箱格式不正确"
// 测试只读属性
console.log('\n--- 测试只读属性 ---');
// "--- 测试只读属性 ---"
try {
user.id = 'new_id';
} catch (error) {
console.log('只读属性错误:', (error as Error).message);
}
// "🚫 属性 id 是只读的"
// "只读属性错误: 属性 id 是只读的"
9.5 参数装饰器——为参数装上"智能检测器" 🎯
参数装饰器就像为每个参数配备了专业的检测设备,能够在方法调用前对参数进行验证、注入和转换。
🔬 参数装饰器的检测职责:精确的参数处理
参数装饰器是最精细的装饰器类型,它们专注于方法参数级别的控制,为每个参数提供精确的处理能力:
1. 💉 依赖注入与服务提供
-
inject
自动注入依赖服务
- 实现控制反转(IoC)模式
- 降低组件间的耦合度
2. ✅ 参数验证与类型保障
-
validateParam
确保参数符合预期
- 提供运行时类型检查
- 实现业务规则验证
3. 🔄 参数转换与适配
- 自动转换参数格式和类型
- 实现参数的标准化处理
- 处理不同数据源的参数适配
4. 📝 元数据收集与反射
- 收集参数的类型信息
- 支持基于反射的高级功能
- 为框架和工具提供元数据
5. 🔗 框架集成与扩展
- 与依赖注入框架无缝集成
- 支持AOP(面向切面编程)
- 实现声明式编程模式
💉 依赖注入:"智能服务提供者"
// 📁 parameter-decorators.ts - 参数装饰器演示
/**
* 依赖注入装饰器工厂
*/
function inject(token: string) {
console.log(`创建依赖注入装甲工厂 (令牌: ${token})`);
return function(target: any, key: string | symbol | undefined, parameterIndex: number) {
console.log(`为参数 ${parameterIndex} 安装依赖注入装甲 (方法: ${String(key)})`);
// 存储注入元数据
const existingTokens = Reflect.getMetadata('inject:tokens', target, key!) || [];
existingTokens[parameterIndex] = token;
Reflect.defineMetadata('inject:tokens', existingTokens, target, key!);
};
}
/**
* 参数验证装饰器工厂
*/
function validateParam(validator: (value: any) => boolean, errorMessage?: string) {
console.log(`创建参数验证装甲工厂`);
return function(target: any, key: string | symbol | undefined, parameterIndex: number) {
console.log(`为参数 ${parameterIndex} 安装验证装甲 (方法: ${String(key)})`);
// 存储验证元数据
const existingValidators = Reflect.getMetadata('validate:params', target, key!) || [];
existingValidators[parameterIndex] = { validator, errorMessage };
Reflect.defineMetadata('validate:params', existingValidators, target, key!);
};
}
/**
* 简单的依赖注入容器
*/
class DIContainer {
private static services = new Map<string, any>();
static register(token: string, service: any) {
console.log(`📦 注册服务: ${token}`);
this.services.set(token, service);
}
static resolve(token: string) {
const service = this.services.get(token);
if (!service) {
throw new Error(`服务未找到: ${token}`);
}
console.log(`🔍 解析服务: ${token}`);
return service;
}
}
/**
* 方法拦截器 - 处理依赖注入和参数验证
*/
function methodInterceptor(target: any, key: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
console.log(`为方法 ${key} 安装拦截器`);
descriptor.value = function(...args: any[]) {
console.log(`🚀 拦截方法调用: ${key}`);
// 处理依赖注入
const injectTokens = Reflect.getMetadata('inject:tokens', target, key) || [];
const validators = Reflect.getMetadata('validate:params', target, key) || [];
const finalArgs = [...args];
// 注入依赖
for (let i = 0; i < injectTokens.length; i++) {
if (injectTokens[i]) {
try {
const service = DIContainer.resolve(injectTokens[i]);
finalArgs[i] = service;
console.log(`💉 注入依赖到参数 ${i}: ${injectTokens[i]}`);
} catch (error) {
console.log(`❌ 依赖注入失败:`, (error as Error).message);
throw error;
}
}
}
// 验证参数
for (let i = 0; i < validators.length; i++) {
if (validators[i] && finalArgs[i] !== undefined) {
const { validator, errorMessage } = validators[i];
const isValid = validator(finalArgs[i]);
console.log(`🔍 验证参数 ${i}: ${isValid ? '✅ 通过' : '❌ 失败'}`);
if (!isValid) {
const error = new Error(errorMessage || `参数 ${i} 验证失败`);
console.log(`💥 ${error.message}`);
throw error;
}
}
}
console.log(`✅ 所有参数处理完成,执行原方法`);
return originalMethod.apply(this, finalArgs);
};
return descriptor;
}
console.log('=== 参数装饰器演示 ===');
// "=== 参数装饰器演示 ==="
// 注册服务
class Logger {
log(message: string) {
console.log(`📝 [Logger] ${message}`);
}
}
class Database {
query(sql: string) {
console.log(`🗄️ [Database] 执行查询: ${sql}`);
return { rows: [`结果 for ${sql}`] };
}
}
DIContainer.register('logger', new Logger());
// "📦 注册服务: logger"
DIContainer.register('database', new Database());
// "📦 注册服务: database"
class UserService {
@methodInterceptor
createUser(
@inject('logger') logger: Logger,
@inject('database') db: Database,
@validateParam(
(name: string) => typeof name === 'string' && name.length >= 2,
'用户名至少需要2个字符'
)
name: string,
@validateParam(
(email: string) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email),
'邮箱格式不正确'
)
email: string
) {
console.log(`🏗️ 创建用户: ${name} (${email})`);
logger.log(`开始创建用户: ${name}`);
const result = db.query(`INSERT INTO users (name, email) VALUES ('${name}', '${email}')`);
logger.log(`用户创建成功: ${name}`);
const user = {
id: Math.random().toString(36).substr(2, 9),
name,
email,
createdAt: new Date().toISOString()
};
console.log(`✅ 用户创建完成:`, user);
return user;
}
@methodInterceptor
updateUser(
@inject('logger') logger: Logger,
@validateParam(
(id: string) => typeof id === 'string' && id.length > 0,
'用户ID不能为空'
)
id: string,
updates: Partial<{ name: string; email: string }>
) {
console.log(`🔄 更新用户: ${id}`);
logger.log(`开始更新用户: ${id}`);
const updatedUser = {
id,
...updates,
updatedAt: new Date().toISOString()
};
logger.log(`用户更新成功: ${id}`);
console.log(`✅ 用户更新完成:`, updatedUser);
return updatedUser;
}
}
// 装饰器安装过程:
// "创建依赖注入装甲工厂 (令牌: logger)"
// "为参数 0 安装依赖注入装甲 (方法: createUser)"
// "创建依赖注入装甲工厂 (令牌: database)"
// "为参数 1 安装依赖注入装甲 (方法: createUser)"
// "创建参数验证装甲工厂"
// "为参数 2 安装验证装甲 (方法: createUser)"
// "创建参数验证装甲工厂"
// "为参数 3 安装验证装甲 (方法: createUser)"
// "为方法 createUser 安装拦截器"
// "创建依赖注入装甲工厂 (令牌: logger)"
// "为参数 0 安装依赖注入装甲 (方法: updateUser)"
// "创建参数验证装甲工厂"
// "为参数 1 安装验证装甲 (方法: updateUser)"
// "为方法 updateUser 安装拦截器"
const userService = new UserService();
console.log('\n--- 测试用户创建 ---');
// "--- 测试用户创建 ---"
// 注意:由于使用了依赖注入,前两个参数会被自动注入
const newUser = userService.createUser(null as any, null as any, '张三', 'zhangsan@example.com');
// "🚀 拦截方法调用: createUser"
// "🔍 解析服务: logger"
// "💉 注入依赖到参数 0: logger"
// "🔍 解析服务: database"
// "💉 注入依赖到参数 1: database"
// "🔍 验证参数 2: ✅ 通过"
// "🔍 验证参数 3: ✅ 通过"
// "✅ 所有参数处理完成,执行原方法"
// "🏗️ 创建用户: 张三 (zhangsan@example.com)"
// "📝 [Logger] 开始创建用户: 张三"
// "🗄️ [Database] 执行查询: INSERT INTO users (name, email) VALUES ('张三', 'zhangsan@example.com')"
// "📝 [Logger] 用户创建成功: 张三"
// "✅ 用户创建完成: {id: 'abc123def', name: '张三', email: 'zhangsan@example.com', createdAt: '2024-01-01T12:00:00.000Z'}"
console.log('\n--- 测试参数验证失败 ---');
// "--- 测试参数验证失败 ---"
// 测试用户名验证失败
try {
userService.createUser(null as any, null as any, 'a', 'invalid-email');
} catch (error) {
console.log('创建用户失败:', (error as Error).message);
}
// "🚀 拦截方法调用: createUser"
// "🔍 解析服务: logger"
// "💉 注入依赖到参数 0: logger"
// "🔍 解析服务: database"
// "💉 注入依赖到参数 1: database"
// "🔍 验证参数 2: ❌ 失败"
// "💥 用户名至少需要2个字符"
// "创建用户失败: 用户名至少需要2个字符"
console.log('\n--- 测试用户更新 ---');
// "--- 测试用户更新 ---"
const updatedUser = userService.updateUser(null as any, 'user_123', { name: '李四' });
// "🚀 拦截方法调用: updateUser"
// "🔍 解析服务: logger"
// "💉 注入依赖到参数 0: logger"
// "🔍 验证参数 1: ✅ 通过"
// "✅ 所有参数处理完成,执行原方法"
// "🔄 更新用户: user_123"
// "📝 [Logger] 开始更新用户: user_123"
// "📝 [Logger] 用户更新成功: user_123"
// "✅ 用户更新完成: {id: 'user_123', name: '李四', updatedAt: '2024-01-01T12:00:01.000Z'}"
9.6 装饰器工厂与组合——"模块化装甲系统" 🏭
装饰器工厂就像是装甲制造工厂,能够根据不同需求生产定制化的装饰器,而装饰器组合则能创造出功能更强大的复合装甲。
🔧 高级装饰器工厂:"智能装甲定制工厂"
// 📁 decorator-factories.ts - 装饰器工厂演示
/**
* 日志装饰器工厂 - 可配置的日志系统
*/
function logWithPrefix(prefix: string, options: {
logArgs?: boolean;
logResult?: boolean;
logTime?: boolean;
logLevel?: 'info' | 'debug' | 'warn' | 'error';
} = {}) {
const { logArgs = true, logResult = true, logTime = true, logLevel = 'info' } = options;
console.log(`创建日志装甲工厂 (前缀: ${prefix}, 级别: ${logLevel})`);
return function(target: any, key: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
console.log(`为方法 ${key} 安装日志装甲`);
descriptor.value = function(...args: any[]) {
const timestamp = new Date().toISOString();
const logPrefix = `[${timestamp}] [${logLevel.toUpperCase()}] [${prefix}]`;
if (logArgs) {
console.log(`${logPrefix} 🚀 调用 ${key},参数:`, args);
} else {
console.log(`${logPrefix} 🚀 调用 ${key}`);
}
const start = logTime ? performance.now() : 0;
try {
const result = originalMethod.apply(this, args);
if (logTime) {
const duration = (performance.now() - start).toFixed(2);
console.log(`${logPrefix} ⏱️ ${key} 耗时 ${duration}ms`);
}
if (logResult) {
console.log(`${logPrefix} ✅ ${key} 返回:`, result);
}
return result;
} catch (error) {
console.log(`${logPrefix} ❌ ${key} 异常:`, (error as Error).message);
throw error;
}
};
return descriptor;
};
}
/**
* 只读装饰器工厂 - 可配置的只读控制
*/
function readOnly(options: {
allowInitialSet?: boolean;
customError?: string;
} = {}) {
const { allowInitialSet = true, customError } = options;
console.log(`创建只读装甲工厂 (允许初始设置: ${allowInitialSet})`);
return function(target: any, key: string) {
console.log(`为属性 ${key} 安装只读装甲`);
const privateKey = `_${key}`;
let isInitialized = false;
Object.defineProperty(target, key, {
get: function() {
const value = this[privateKey];
console.log(`🔍 读取只读属性 ${key}: ${JSON.stringify(value)}`);
return value;
},
set: function(value) {
if (!allowInitialSet || isInitialized) {
const error = new Error(customError || `属性 ${key} 是只读的`);
console.log(`🚫 ${error.message}`);
throw error;
}
console.log(`✏️ 初始设置只读属性 ${key}: ${JSON.stringify(value)}`);
this[privateKey] = value;
isInitialized = true;
},
enumerable: true,
configurable: false
});
};
}
/**
* 装饰器组合工厂 - 创建复合装饰器
*/
function createCompositeDecorator(...decorators: any[]) {
console.log(`创建复合装甲 (${decorators.length}个装饰器)`);
return function(target: any, key: string, descriptor?: PropertyDescriptor) {
console.log(`应用复合装甲到 ${key}`);
// 从右到左应用装饰器(符合装饰器的执行顺序)
for (let i = decorators.length - 1; i >= 0; i--) {
const decorator = decorators[i];
if (descriptor) {
// 方法装饰器
descriptor = decorator(target, key, descriptor) || descriptor;
} else {
// 属性装饰器
decorator(target, key);
}
}
return descriptor;
};
}
console.log('=== 装饰器工厂演示 ===');
// "=== 装饰器工厂演示 ==="
class PaymentService {
@readOnly({ allowInitialSet: true, customError: '支付服务ID不可修改' })
serviceId: string;
@readOnly({ allowInitialSet: false })
version: string = '1.0.0';
constructor(serviceId: string) {
console.log(`初始化支付服务: ${serviceId}`);
this.serviceId = serviceId;
}
@logWithPrefix('PaymentService', {
logArgs: true,
logResult: true,
logTime: true,
logLevel: 'info'
})
processPayment(amount: number, currency: string = 'CNY') {
console.log(`💳 处理支付: ${amount} ${currency}`);
// 模拟支付处理
if (amount <= 0) {
throw new Error('支付金额必须大于0');
}
const paymentId = Math.random().toString(36).substr(2, 9);
const result = {
paymentId,
amount,
currency,
status: 'success',
timestamp: Date.now()
};
console.log(`✅ 支付处理成功:`, result);
return result;
}
@logWithPrefix('PaymentService', {
logArgs: false,
logResult: false,
logTime: true,
logLevel: 'debug'
})
validatePayment(paymentData: any) {
console.log(`🔍 验证支付数据`);
// 模拟验证逻辑
const isValid = paymentData && paymentData.amount > 0;
console.log(`验证结果: ${isValid ? '✅ 有效' : '❌ 无效'}`);
return isValid;
}
}
// 装饰器安装过程:
// "创建只读装甲工厂 (允许初始设置: true)"
// "为属性 serviceId 安装只读装甲"
// "创建只读装甲工厂 (允许初始设置: false)"
// "为属性 version 安装只读装甲"
// "创建日志装甲工厂 (前缀: PaymentService, 级别: info)"
// "为方法 processPayment 安装日志装甲"
// "创建日志装甲工厂 (前缀: PaymentService, 级别: debug)"
// "为方法 validatePayment 安装日志装甲"
const paymentService = new PaymentService('pay_service_001');
// "初始化支付服务: pay_service_001"
// "✏️ 初始设置只读属性 serviceId: \"pay_service_001\""
console.log('\n--- 测试支付处理 ---');
// "--- 测试支付处理 ---"
const payment = paymentService.processPayment(100, 'USD');
// "[2024-01-01T12:00:00.000Z] [INFO] [PaymentService] 🚀 调用 processPayment,参数: [100, 'USD']"
// "💳 处理支付: 100 USD"
// "✅ 支付处理成功: {paymentId: 'abc123def', amount: 100, currency: 'USD', status: 'success', timestamp: 1704067200000}"
// "[2024-01-01T12:00:00.050Z] [INFO] [PaymentService] ⏱️ processPayment 耗时 50.25ms"
// "[2024-01-01T12:00:00.050Z] [INFO] [PaymentService] ✅ processPayment 返回: {paymentId: 'abc123def', amount: 100, currency: 'USD', status: 'success', timestamp: 1704067200000}"
console.log('\n--- 测试支付验证 ---');
// "--- 测试支付验证 ---"
const isValid = paymentService.validatePayment({ amount: 50 });
// "[2024-01-01T12:00:00.100Z] [DEBUG] [PaymentService] 🚀 调用 validatePayment"
// "🔍 验证支付数据"
// "验证结果: ✅ 有效"
// "[2024-01-01T12:00:00.105Z] [DEBUG] [PaymentService] ⏱️ validatePayment 耗时 5.20ms"
console.log('\n--- 测试只读属性 ---');
// "--- 测试只读属性 ---"
// 读取属性
console.log('服务ID:', paymentService.serviceId);
// "🔍 读取只读属性 serviceId: \"pay_service_001\""
// "服务ID: pay_service_001"
console.log('版本:', paymentService.version);
// "🔍 读取只读属性 version: \"1.0.0\""
// "版本: 1.0.0"
// 测试修改只读属性
try {
paymentService.serviceId = 'new_id';
} catch (error) {
console.log('修改服务ID失败:', (error as Error).message);
}
// "🚫 支付服务ID不可修改"
// "修改服务ID失败: 支付服务ID不可修改"
try {
paymentService.version = '2.0.0';
} catch (error) {
console.log('修改版本失败:', (error as Error).message);
}
// "🚫 属性 version 是只读的"
// "修改版本失败: 属性 version 是只读的"
9.7 实战案例——构建"智能API管理系统" 🚀
让我们通过一个完整的实战案例,展示如何使用装饰器构建一个功能强大的API管理系统,就像为整个API服务穿上了全套智能装甲。
🏗️ 完整的API服务系统
// 📁 api-management-system.ts - 完整的API管理系统
/**
* API路由装饰器工厂 - 定义API端点
*/
function apiRoute(path: string, method: 'GET' | 'POST' | 'PUT' | 'DELETE' = 'GET') {
console.log(`创建API路由装甲工厂 (${method} ${path})`);
return function(target: any, key: string, descriptor: PropertyDescriptor) {
console.log(`为方法 ${key} 安装API路由装甲`);
// 存储路由元数据
Reflect.defineMetadata('api:path', path, target, key);
Reflect.defineMetadata('api:method', method, target, key);
return descriptor;
};
}
/**
* 权限验证装饰器工厂
*/
function requireAuth(roles: string[] = []) {
console.log(`创建权限验证装甲工厂 (角色: ${roles.join(', ')})`);
return function(target: any, key: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
console.log(`为方法 ${key} 安装权限验证装甲`);
descriptor.value = function(request: any, ...args: any[]) {
console.log(`🔐 验证API权限: ${key}`);
// 模拟权限验证
const userRole = request.user?.role || 'guest';
console.log(`👤 用户角色: ${userRole}`);
if (roles.length > 0 && !roles.includes(userRole)) {
const error = new Error(`权限不足,需要角色: ${roles.join(', ')}`);
console.log(`🚫 ${error.message}`);
throw error;
}
console.log(`✅ 权限验证通过`);
return originalMethod.apply(this, [request, ...args]);
};
return descriptor;
};
}
/**
* 请求限流装饰器工厂
*/
function rateLimit(maxRequests: number, windowMs: number) {
console.log(`创建限流装甲工厂 (${maxRequests}次/${windowMs}ms)`);
const requestCounts = new Map<string, { count: number; resetTime: number }>();
return function(target: any, key: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
console.log(`为方法 ${key} 安装限流装甲`);
descriptor.value = function(request: any, ...args: any[]) {
const clientId = request.ip || 'unknown';
const now = Date.now();
console.log(`🚦 检查限流: ${key} (客户端: ${clientId})`);
let clientData = requestCounts.get(clientId);
if (!clientData || now > clientData.resetTime) {
clientData = { count: 0, resetTime: now + windowMs };
requestCounts.set(clientId, clientData);
console.log(`🔄 重置限流计数器: ${clientId}`);
}
if (clientData.count >= maxRequests) {
const error = new Error(`请求过于频繁,请稍后再试`);
console.log(`🚫 ${error.message} (${clientData.count}/${maxRequests})`);
throw error;
}
clientData.count++;
console.log(`✅ 限流检查通过 (${clientData.count}/${maxRequests})`);
return originalMethod.apply(this, [request, ...args]);
};
return descriptor;
};
}
/**
* 响应缓存装饰器工厂
*/
function cacheResponse(ttl: number = 60000) {
console.log(`创建响应缓存装甲工厂 (TTL: ${ttl}ms)`);
const cache = new Map<string, { data: any; timestamp: number }>();
return function(target: any, key: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
console.log(`为方法 ${key} 安装响应缓存装甲`);
descriptor.value = function(request: any, ...args: any[]) {
const cacheKey = `${key}_${JSON.stringify(request.params || {})}_${JSON.stringify(request.query || {})}`;
const now = Date.now();
console.log(`💾 检查响应缓存: ${cacheKey}`);
const cached = cache.get(cacheKey);
if (cached && (now - cached.timestamp) < ttl) {
console.log(`✅ 缓存命中,返回缓存数据`);
return cached.data;
}
console.log(`🔍 缓存未命中,执行方法`);
const result = originalMethod.apply(this, [request, ...args]);
cache.set(cacheKey, { data: result, timestamp: now });
console.log(`💾 结果已缓存`);
return result;
};
return descriptor;
};
}
/**
* API监控装饰器
*/
function apiMonitor(target: any, key: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
console.log(`为方法 ${key} 安装API监控装甲`);
descriptor.value = function(request: any, ...args: any[]) {
const startTime = Date.now();
const path = Reflect.getMetadata('api:path', target, key) || 'unknown';
const method = Reflect.getMetadata('api:method', target, key) || 'unknown';
console.log(`📊 [API监控] ${method} ${path} 开始处理`);
console.log(`📊 [API监控] 请求来源: ${request.ip || 'unknown'}`);
console.log(`📊 [API监控] 用户代理: ${request.userAgent || 'unknown'}`);
try {
const result = originalMethod.apply(this, [request, ...args]);
const duration = Date.now() - startTime;
console.log(`📊 [API监控] ${method} ${path} 处理成功`);
console.log(`📊 [API监控] 响应时间: ${duration}ms`);
console.log(`📊 [API监控] 响应大小: ${JSON.stringify(result).length} 字符`);
return result;
} catch (error) {
const duration = Date.now() - startTime;
console.log(`📊 [API监控] ${method} ${path} 处理失败`);
console.log(`📊 [API监控] 错误信息: ${(error as Error).message}`);
console.log(`📊 [API监控] 失败时间: ${duration}ms`);
throw error;
}
};
return descriptor;
}
console.log('=== API管理系统演示 ===');
// "=== API管理系统演示 ==="
class UserController {
@apiRoute('/users', 'GET')
@apiMonitor
@cacheResponse(30000) // 30秒缓存
@rateLimit(10, 60000) // 每分钟最多10次请求
getUsers(request: any) {
console.log(`📋 获取用户列表`);
// 模拟数据库查询
const users = [
{ id: 1, name: '张三', email: 'zhangsan@example.com', role: 'user' },
{ id: 2, name: '李四', email: 'lisi@example.com', role: 'admin' },
{ id: 3, name: '王五', email: 'wangwu@example.com', role: 'user' }
];
console.log(`✅ 返回 ${users.length} 个用户`);
return { success: true, data: users, total: users.length };
}
@apiRoute('/users/:id', 'GET')
@apiMonitor
@cacheResponse(60000) // 1分钟缓存
@rateLimit(20, 60000) // 每分钟最多20次请求
getUserById(request: any) {
const userId = request.params.id;
console.log(`👤 获取用户详情: ${userId}`);
// 模拟数据库查询
const user = {
id: userId,
name: `用户${userId}`,
email: `user${userId}@example.com`,
role: 'user',
createdAt: '2024-01-01T00:00:00.000Z',
lastLogin: new Date().toISOString()
};
console.log(`✅ 返回用户详情:`, user);
return { success: true, data: user };
}
@apiRoute('/users', 'POST')
@apiMonitor
@requireAuth(['admin', 'moderator'])
@rateLimit(5, 60000) // 每分钟最多5次创建请求
createUser(request: any) {
console.log(`🏗️ 创建新用户`);
console.log(`📝 用户数据:`, request.body);
// 模拟用户创建
const newUser = {
id: Math.random().toString(36).substr(2, 9),
...request.body,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString()
};
console.log(`✅ 用户创建成功:`, newUser);
return { success: true, data: newUser, message: '用户创建成功' };
}
@apiRoute('/users/:id', 'PUT')
@apiMonitor
@requireAuth(['admin', 'moderator'])
@rateLimit(10, 60000) // 每分钟最多10次更新请求
updateUser(request: any) {
const userId = request.params.id;
console.log(`🔄 更新用户: ${userId}`);
console.log(`📝 更新数据:`, request.body);
// 模拟用户更新
const updatedUser = {
id: userId,
...request.body,
updatedAt: new Date().toISOString()
};
console.log(`✅ 用户更新成功:`, updatedUser);
return { success: true, data: updatedUser, message: '用户更新成功' };
}
@apiRoute('/users/:id', 'DELETE')
@apiMonitor
@requireAuth(['admin'])
@rateLimit(3, 60000) // 每分钟最多3次删除请求
deleteUser(request: any) {
const userId = request.params.id;
console.log(`🗑️ 删除用户: ${userId}`);
// 模拟用户删除
console.log(`✅ 用户删除成功: ${userId}`);
return { success: true, message: `用户 ${userId} 已删除` };
}
}
// 装饰器安装过程:
// "创建响应缓存装甲工厂 (TTL: 30000ms)"
// "创建限流装甲工厂 (10次/60000ms)"
// "为方法 getUsers 安装限流装甲"
// "为方法 getUsers 安装响应缓存装甲"
// "为方法 getUsers 安装API监控装甲"
// "创建API路由装甲工厂 (GET /users)"
// "为方法 getUsers 安装API路由装甲"
// ... (其他方法的装饰器安装过程)
const userController = new UserController();
console.log('\n--- 测试API调用 ---');
// "--- 测试API调用 ---"
// 模拟请求对象
const createMockRequest = (overrides: any = {}) => ({
ip: '192.168.1.100',
userAgent: 'Mozilla/5.0 (Test Browser)',
user: { id: 1, role: 'admin' },
params: {},
query: {},
body: {},
...overrides
});
// 测试获取用户列表
console.log('\n=== 测试获取用户列表 ===');
const getUsersRequest = createMockRequest();
const users = userController.getUsers(getUsersRequest);
// "🚦 检查限流: getUsers (客户端: 192.168.1.100)"
// "🔄 重置限流计数器: 192.168.1.100"
// "✅ 限流检查通过 (1/10)"
// "💾 检查响应缓存: getUsers_{}_{}"
// "🔍 缓存未命中,执行方法"
// "📊 [API监控] GET /users 开始处理"
// "📊 [API监控] 请求来源: 192.168.1.100"
// "📊 [API监控] 用户代理: Mozilla/5.0 (Test Browser)"
// "📋 获取用户列表"
// "✅ 返回 3 个用户"
// "📊 [API监控] GET /users 处理成功"
// "📊 [API监控] 响应时间: 5ms"
// "📊 [API监控] 响应大小: 245 字符"
// "💾 结果已缓存"
// 测试缓存命中
console.log('\n=== 测试缓存命中 ===');
const cachedUsers = userController.getUsers(getUsersRequest);
// "🚦 检查限流: getUsers (客户端: 192.168.1.100)"
// "✅ 限流检查通过 (2/10)"
// "💾 检查响应缓存: getUsers_{}_{}"
// "✅ 缓存命中,返回缓存数据"
// 测试获取单个用户
console.log('\n=== 测试获取单个用户 ===');
const getUserRequest = createMockRequest({ params: { id: '123' } });
const user = userController.getUserById(getUserRequest);
// "🚦 检查限流: getUserById (客户端: 192.168.1.100)"
// "🔄 重置限流计数器: 192.168.1.100"
// "✅ 限流检查通过 (1/20)"
// "💾 检查响应缓存: getUserById_{\"id\":\"123\"}_{}"
// "🔍 缓存未命中,执行方法"
// "📊 [API监控] GET /users/:id 开始处理"
// "📊 [API监控] 请求来源: 192.168.1.100"
// "📊 [API监控] 用户代理: Mozilla/5.0 (Test Browser)"
// "👤 获取用户详情: 123"
// "✅ 返回用户详情: {id: '123', name: '用户123', email: 'user123@example.com', role: 'user', createdAt: '2024-01-01T00:00:00.000Z', lastLogin: '2024-01-01T12:00:00.000Z'}"
// "📊 [API监控] GET /users/:id 处理成功"
// "📊 [API监控] 响应时间: 3ms"
// "📊 [API监控] 响应大小: 185 字符"
// "💾 结果已缓存"
// 测试创建用户(需要权限)
console.log('\n=== 测试创建用户 ===');
const createUserRequest = createMockRequest({
body: { name: '新用户', email: 'newuser@example.com', role: 'user' }
});
const newUser = userController.createUser(createUserRequest);
// "🚦 检查限流: createUser (客户端: 192.168.1.100)"
// "🔄 重置限流计数器: 192.168.1.100"
// "✅ 限流检查通过 (1/5)"
// "🔐 验证API权限: createUser"
// "👤 用户角色: admin"
// "✅ 权限验证通过"
// "📊 [API监控] POST /users 开始处理"
// "📊 [API监控] 请求来源: 192.168.1.100"
// "📊 [API监控] 用户代理: Mozilla/5.0 (Test Browser)"
// "🏗️ 创建新用户"
// "📝 用户数据: {name: '新用户', email: 'newuser@example.com', role: 'user'}"
// "✅ 用户创建成功: {id: 'abc123def', name: '新用户', email: 'newuser@example.com', role: 'user', createdAt: '2024-01-01T12:00:00.000Z', updatedAt: '2024-01-01T12:00:00.000Z'}"
// "📊 [API监控] POST /users 处理成功"
// "📊 [API监控] 响应时间: 8ms"
// "📊 [API监控] 响应大小: 156 字符"
// 测试权限不足
console.log('\n=== 测试权限不足 ===');
const unauthorizedRequest = createMockRequest({
user: { id: 2, role: 'user' }, // 普通用户尝试创建用户
body: { name: '测试用户', email: 'test@example.com' }
});
try {
userController.createUser(unauthorizedRequest);
} catch (error) {
console.log('权限验证失败:', (error as Error).message);
}
// "🚦 检查限流: createUser (客户端: 192.168.1.100)"
// "✅ 限流检查通过 (2/5)"
// "🔐 验证API权限: createUser"
// "👤 用户角色: user"
// "🚫 权限不足,需要角色: admin, moderator"
// "权限验证失败: 权限不足,需要角色: admin, moderator"
console.log('\n=== API管理系统演示完成 ===');
// "=== API管理系统演示完成 ==="
9.8 装饰器最佳实践与设计模式 📚
🎯 装饰器设计原则
原则 |
说明 |
示例 |
单一职责 |
每个装饰器只负责一个功能 |
@log 只负责日志,@cache 只负责缓存 |
可组合性 |
装饰器可以自由组合使用 |
@log @cache @validate |
配置灵活 |
通过工厂函数提供配置选项 |
@cache({ ttl: 5000, maxSize: 100 }) |
无侵入性 |
不改变原有代码逻辑 |
装饰器只是增强,不修改核心逻辑 |
错误处理 |
优雅处理异常情况 |
装饰器失败不应影响核心功能 |
🔧 常用装饰器模式
// 📁 decorator-patterns.ts - 装饰器设计模式
/**
* 1. 代理模式 - 控制对象访问
*/
function proxy(handler: ProxyHandler<any>) {
return function<T extends { new (...args: any[]): {} }>(constructor: T) {
return class extends constructor {
constructor(...args: any[]) {
super(...args);
return new Proxy(this, handler);
}
} as T;
};
}
/**
* 2. 观察者模式 - 事件监听
*/
function observable(target: any, key: string) {
const privateKey = `_${key}`;
const listeners: Function[] = [];
Object.defineProperty(target, key, {
get() { return this[privateKey]; },
set(value) {
const oldValue = this[privateKey];
this[privateKey] = value;
listeners.forEach(listener => listener(value, oldValue));
}
});
target[`${key}Listeners`] = listeners;
}
/**
* 3. 策略模式 - 算法切换
*/
function strategy(strategies: { [key: string]: Function }) {
return function(target: any, key: string, descriptor: PropertyDescriptor) {
descriptor.value = function(strategyName: string, ...args: any[]) {
const strategy = strategies[strategyName];
if (!strategy) {
throw new Error(`策略不存在: ${strategyName}`);
}
return strategy.apply(this, args);
};
};
}
/**
* 4. 工厂模式 - 对象创建
*/
function factory(factories: { [key: string]: () => any }) {
return function(target: any, key: string, descriptor: PropertyDescriptor) {
descriptor.value = function(type: string, ...args: any[]) {
const factory = factories[type];
if (!factory) {
throw new Error(`工厂不存在: ${type}`);
}
return factory(...args);
};
};
}
console.log('=== 装饰器设计模式演示 ===');
// "=== 装饰器设计模式演示 ==="
@proxy({
get(target, prop) {
console.log(`🔍 访问属性: ${String(prop)}`);
return target[prop];
},
set(target, prop, value) {
console.log(`✏️ 设置属性: ${String(prop)} = ${value}`);
target[prop] = value;
return true;
}
})
class ProxyExample {
name: string = 'test';
getName() {
return this.name;
}
}
class ObserverExample {
@observable
status: string = 'idle';
constructor() {
// 添加状态变化监听器
(this as any).statusListeners.push((newValue: string, oldValue: string) => {
console.log(`📢 状态变化: ${oldValue} -> ${newValue}`);
});
}
}
class StrategyExample {
@strategy({
bubble: function(arr: number[]) {
console.log('🫧 使用冒泡排序');
return arr.sort((a, b) => a - b);
},
quick: function(arr: number[]) {
console.log('⚡ 使用快速排序');
return arr.sort((a, b) => a - b);
}
})
sort(strategy: string, arr: number[]): number[] {
// 这个方法会被装饰器替换
return arr;
}
}
class FactoryExample {
@factory({
user: () => ({ type: 'user', permissions: ['read'] }),
admin: () => ({ type: 'admin', permissions: ['read', 'write', 'delete'] }),
guest: () => ({ type: 'guest', permissions: [] })
})
createRole(type: string): any {
// 这个方法会被装饰器替换
return null;
}
}
// 测试代理模式
console.log('\n--- 代理模式测试 ---');
const proxyObj = new ProxyExample();
// "🔍 访问属性: name"
// "✏️ 设置属性: name = test"
const name = proxyObj.getName();
// "🔍 访问属性: getName"
// "🔍 访问属性: name"
proxyObj.name = 'updated';
// "✏️ 设置属性: name = updated"
// 测试观察者模式
console.log('\n--- 观察者模式测试 ---');
const observer = new ObserverExample();
observer.status = 'loading';
// "📢 状态变化: idle -> loading"
observer.status = 'complete';
// "📢 状态变化: loading -> complete"
// 测试策略模式
console.log('\n--- 策略模式测试 ---');
const strategy = new StrategyExample();
const sorted1 = strategy.sort('bubble', [3, 1, 4, 1, 5]);
// "🫧 使用冒泡排序"
const sorted2 = strategy.sort('quick', [9, 2, 6, 5, 3]);
// "⚡ 使用快速排序"
// 测试工厂模式
console.log('\n--- 工厂模式测试 ---');
const factory = new FactoryExample();
const userRole = factory.createRole('user');
console.log('用户角色:', userRole);
// "用户角色: {type: 'user', permissions: ['read']}"
const adminRole = factory.createRole('admin');
console.log('管理员角色:', adminRole);
// "管理员角色: {type: 'admin', permissions: ['read', 'write', 'delete']}"
9.9 装饰器在流行框架中的应用 🌟
🌟 Vue风格装饰器
// 📁 vue-style-decorators.ts - Vue风格装饰器
/**
* Vue组件装饰器 - 模拟Vue组件
*/
function VueComponent(config: { name: string; template: string; styles?: string[] }) {
console.log(`创建Vue组件装甲: ${config.name}`);
return function<T extends { new (...args: any[]): {} }>(constructor: T) {
console.log(`为类 ${constructor.name} 安装Vue组件装甲`);
// 存储组件元数据
Reflect.defineMetadata('vue:name', config.name, constructor);
Reflect.defineMetadata('vue:template', config.template, constructor);
Reflect.defineMetadata('vue:styles', config.styles || [], constructor);
return constructor;
};
}
/**
* Vue属性装饰器 - 模拟Vue Prop
*/
function Prop(options?: { type?: any; default?: any; required?: boolean }) {
console.log(`创建Vue属性装甲${options ? ` (类型: ${options.type?.name || 'any'})` : ''}`);
return function(target: any, key: string) {
console.log(`为属性 ${key} 安装Vue属性装甲`);
const props = Reflect.getMetadata('vue:props', target.constructor) || [];
props.push({
property: key,
type: options?.type || String,
default: options?.default,
required: options?.required || false
});
Reflect.defineMetadata('vue:props', props, target.constructor);
};
}
/**
* Vue事件装饰器 - 模拟Vue Emit
*/
function Emit(eventName?: string) {
console.log(`创建Vue事件装甲${eventName ? ` (事件名: ${eventName})` : ''}`);
return function(target: any, key: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
console.log(`为方法 ${key} 安装Vue事件装甲`);
descriptor.value = function(...args: any[]) {
const result = originalMethod.apply(this, args);
const event = eventName || key.replace(/^on/, '').toLowerCase();
console.log(`📡 Vue事件发射: ${event}`, result);
// 模拟Vue的$emit
if (this.$emit) {
this.$emit(event, result);
}
return result;
};
return descriptor;
};
}
/**
* Vue生命周期装饰器
*/
function VueLifecycle(hook: 'mounted' | 'unmounted' | 'updated') {
console.log(`创建Vue生命周期装甲: ${hook}`);
return function(target: any, key: string, descriptor: PropertyDescriptor) {
console.log(`为方法 ${key} 安装Vue生命周期装甲`);
const hooks = Reflect.getMetadata('vue:hooks', target.constructor) || {};
hooks[hook] = key;
Reflect.defineMetadata('vue:hooks', hooks, target.constructor);
return descriptor;
};
}
console.log('=== Vue风格装饰器演示 ===');
// "=== Vue风格装饰器演示 ==="
@VueComponent({
name: 'UserCard',
template: `
<div class="user-card">
<h3>{{ name }}</h3>
<p>{{ email }}</p>
<button @click="handleEdit">编辑</button>
</div>
`,
styles: ['.user-card { border: 1px solid #ccc; padding: 16px; border-radius: 8px; }']
})
class UserCardComponent {
@Prop({ type: String, required: true })
name: string = '';
@Prop({ type: String, default: 'unknown@example.com' })
email: string = '';
// 模拟Vue的$emit方法
$emit?: (event: string, data: any) => void;
@VueLifecycle('mounted')
onMounted() {
console.log(`🎬 Vue组件已挂载`);
console.log(`👤 用户: ${this.name} (${this.email})`);
}
@VueLifecycle('unmounted')
onUnmounted() {
console.log(`🎬 Vue组件已卸载`);
}
@Emit('user-edit')
handleEdit() {
console.log(`✏️ 编辑用户: ${this.name}`);
return { name: this.name, email: this.email };
}
}
// 装饰器安装过程:
// "创建Vue组件装甲: UserCard"
// "为类 UserCardComponent 安装Vue组件装甲"
// "创建Vue属性装甲 (类型: String)"
// "为属性 name 安装Vue属性装甲"
// "创建Vue属性装甲 (类型: String)"
// "为属性 email 安装Vue属性装甲"
// "创建Vue生命周期装甲: mounted"
// "为方法 onMounted 安装Vue生命周期装甲"
// "创建Vue生命周期装甲: unmounted"
// "为方法 onUnmounted 安装Vue生命周期装甲"
// "创建Vue事件装甲 (事件名: user-edit)"
// "为方法 handleEdit 安装Vue事件装甲"
// 测试Vue组件
const vueUserCard = new UserCardComponent();
vueUserCard.name = '李四';
vueUserCard.email = 'lisi@example.com';
// 模拟Vue的$emit
vueUserCard.$emit = (event: string, data: any) => {
console.log(`Vue事件监听: ${event}`, data);
};
// 模拟组件挂载
vueUserCard.onMounted();
// "🎬 Vue组件已挂载"
// "👤 用户: 李四 (lisi@example.com)"
// 触发编辑事件
vueUserCard.handleEdit();
// "✏️ 编辑用户: 李四"
// "📡 Vue事件发射: user-edit {name: '李四', email: 'lisi@example.com'}"
// "Vue事件监听: user-edit {name: '李四', email: 'lisi@example.com'}"
// 获取Vue组件元数据
const vueName = Reflect.getMetadata('vue:name', UserCardComponent);
const vueProps = Reflect.getMetadata('vue:props', UserCardComponent);
const vueHooks = Reflect.getMetadata('vue:hooks', UserCardComponent);
console.log('\n--- Vue组件元数据 ---');
console.log('组件名:', vueName);
// "组件名: UserCard"
console.log('属性配置:', vueProps);
// "属性配置: [{property: 'name', type: String, required: true}, {property: 'email', type: String, default: 'unknown@example.com', required: false}]"
console.log('生命周期钩子:', vueHooks);
// "生命周期钩子: {mounted: 'onMounted', unmounted: 'onUnmounted'}"
🚀 NestJS风格装饰器
// 📁 nestjs-style-decorators.ts - NestJS风格装饰器
/**
* NestJS控制器装饰器
*/
function Controller(path: string = '') {
console.log(`创建NestJS控制器装甲: ${path}`);
return function<T extends { new (...args: any[]): {} }>(constructor: T) {
console.log(`为类 ${constructor.name} 安装控制器装甲`);
// 存储控制器元数据
Reflect.defineMetadata('controller:path', path, constructor);
Reflect.defineMetadata('controller:routes', [], constructor);
return constructor;
};
}
/**
* HTTP方法装饰器工厂
*/
function createHttpMethodDecorator(method: string) {
return function(path: string = '') {
console.log(`创建${method}路由装甲: ${path}`);
return function(target: any, key: string, descriptor: PropertyDescriptor) {
console.log(`为方法 ${key} 安装${method}路由装甲`);
// 存储路由元数据
Reflect.defineMetadata('route:method', method, target, key);
Reflect.defineMetadata('route:path', path, target, key);
const routes = Reflect.getMetadata('controller:routes', target.constructor) || [];
routes.push({ method: key, httpMethod: method, path });
Reflect.defineMetadata('controller:routes', routes, target.constructor);
return descriptor;
};
};
}
// HTTP方法装饰器
const Get = createHttpMethodDecorator('GET');
const Post = createHttpMethodDecorator('POST');
const Put = createHttpMethodDecorator('PUT');
const Delete = createHttpMethodDecorator('DELETE');
/**
* 依赖注入装饰器
*/
function Injectable() {
console.log(`创建可注入服务装甲`);
return function<T extends { new (...args: any[]): {} }>(constructor: T) {
console.log(`为类 ${constructor.name} 安装可注入装甲`);
Reflect.defineMetadata('injectable', true, constructor);
return constructor;
};
}
/**
* 参数装饰器 - Body
*/
function Body() {
console.log(`创建请求体装甲`);
return function(target: any, key: string, parameterIndex: number) {
console.log(`为方法 ${key} 的参数 ${parameterIndex} 安装请求体装甲`);
const existingParams = Reflect.getMetadata('route:params', target, key) || [];
existingParams.push({ index: parameterIndex, type: 'body' });
Reflect.defineMetadata('route:params', existingParams, target, key);
};
}
/**
* 参数装饰器 - Param
*/
function Param(name?: string) {
console.log(`创建路径参数装甲${name ? ` (${name})` : ''}`);
return function(target: any, key: string, parameterIndex: number) {
console.log(`为方法 ${key} 的参数 ${parameterIndex} 安装路径参数装甲`);
const existingParams = Reflect.getMetadata('route:params', target, key) || [];
existingParams.push({ index: parameterIndex, type: 'param', name });
Reflect.defineMetadata('route:params', existingParams, target, key);
};
}
/**
* 管道装饰器 - 数据验证
*/
function UsePipes(...pipes: any[]) {
console.log(`创建管道装甲: ${pipes.map(p => p.name).join(', ')}`);
return function(target: any, key: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
console.log(`为方法 ${key} 安装管道装甲`);
descriptor.value = function(...args: any[]) {
console.log(`🔧 执行管道验证: ${key}`);
// 模拟管道处理
pipes.forEach((pipe, index) => {
if (args[index] !== undefined) {
console.log(`📋 管道 ${pipe.name} 处理参数 ${index}:`, args[index]);
}
});
return originalMethod.apply(this, args);
};
return descriptor;
};
}
console.log('=== NestJS风格装饰器演示 ===');
// "=== NestJS风格装饰器演示 ==="
// 模拟验证管道
class ValidationPipe {
static name = 'ValidationPipe';
}
class ParseIntPipe {
static name = 'ParseIntPipe';
}
@Injectable()
class UserService {
findAll() {
console.log(`📋 查询所有用户`);
return [{ id: 1, name: '张三' }, { id: 2, name: '李四' }];
}
findOne(id: number) {
console.log(`👤 查询用户: ${id}`);
return { id, name: `用户${id}` };
}
create(userData: any) {
console.log(`🏗️ 创建用户:`, userData);
return { id: Date.now(), ...userData };
}
}
@Controller('users')
class UserController {
constructor(private userService: UserService) {}
@Get()
@UsePipes(ValidationPipe)
findAll() {
console.log(`🔍 处理获取所有用户请求`);
return this.userService.findAll();
}
@Get(':id')
@UsePipes(ParseIntPipe)
findOne(@Param('id') id: number) {
console.log(`🔍 处理获取单个用户请求: ${id}`);
return this.userService.findOne(id);
}
@Post()
@UsePipes(ValidationPipe)
create(@Body() createUserDto: any) {
console.log(`🏗️ 处理创建用户请求`);
return this.userService.create(createUserDto);
}
}
// 装饰器安装过程:
// "创建可注入服务装甲"
// "为类 UserService 安装可注入装甲"
// "创建NestJS控制器装甲: users"
// "为类 UserController 安装控制器装甲"
// "创建GET路由装甲: "
// "为方法 findAll 安装GET路由装甲"
// "创建管道装甲: ValidationPipe"
// "为方法 findAll 安装管道装甲"
// "创建GET路由装甲: :id"
// "为方法 findOne 安装GET路由装甲"
// "创建路径参数装甲 (id)"
// "为方法 findOne 的参数 0 安装路径参数装甲"
// "创建POST路由装甲: "
// "为方法 create 安装POST路由装甲"
// "创建请求体装甲"
// "为方法 create 的参数 0 安装请求体装甲"
// 测试NestJS控制器
const userService = new UserService();
const userController = new UserController(userService);
console.log('\n--- 测试NestJS路由 ---');
// "--- 测试NestJS路由 ---"
// 测试GET /users
userController.findAll();
// "🔧 执行管道验证: findAll"
// "📋 管道 ValidationPipe 处理参数 0: undefined"
// "🔍 处理获取所有用户请求"
// "📋 查询所有用户"
// 测试GET /users/:id
userController.findOne(1);
// "🔧 执行管道验证: findOne"
// "📋 管道 ParseIntPipe 处理参数 0: 1"
// "🔍 处理获取单个用户请求: 1"
// "👤 查询用户: 1"
// 测试POST /users
userController.create({ name: '王五', email: 'wangwu@example.com' });
// "🔧 执行管道验证: create"
// "📋 管道 ValidationPipe 处理参数 0: {name: '王五', email: 'wangwu@example.com'}"
// "🏗️ 处理创建用户请求"
// "🏗️ 创建用户: {name: '王五', email: 'wangwu@example.com'}"
// 获取NestJS元数据
const controllerPath = Reflect.getMetadata('controller:path', UserController);
const controllerRoutes = Reflect.getMetadata('controller:routes', UserController);
const isInjectable = Reflect.getMetadata('injectable', UserService);
console.log('\n--- NestJS元数据 ---');
console.log('控制器路径:', controllerPath);
// "控制器路径: users"
console.log('路由配置:', controllerRoutes);
// "路由配置: [{method: 'findAll', httpMethod: 'GET', path: ''}, {method: 'findOne', httpMethod: 'GET', path: ':id'}, {method: 'create', httpMethod: 'POST', path: ''}]"
console.log('服务可注入:', isInjectable);
// "服务可注入: true"
9.10 核心收获与进阶方向 🎓
🎯 本章核心收获
装饰器类型 |
核心功能 |
应用场景 |
最佳实践 |
类装饰器 |
增强整个类 |
单例、日志、缓存 |
保持类的原有接口 |
方法装饰器 |
增强方法行为 |
权限、监控、重试 |
处理异步和错误 |
属性装饰器 |
控制属性访问 |
验证、转换、只读 |
使用私有存储 |
参数装饰器 |
处理参数 |
依赖注入、验证 |
配合元数据使用 |
🚀 实用技能掌握
// 📁 practical-skills.ts - 实用技能总结
/**
* 技能1: 装饰器组合策略
*/
const createApiEndpoint = (
path: string,
method: string,
options: {
auth?: string[];
cache?: number;
rateLimit?: { requests: number; window: number };
} = {}
) => {
const decorators = [];
// 基础路由
decorators.push(apiRoute(path, method as any));
// 监控(总是添加)
decorators.push(apiMonitor);
// 权限控制
if (options.auth) {
decorators.push(requireAuth(options.auth));
}
// 缓存
if (options.cache) {
decorators.push(cacheResponse(options.cache));
}
// 限流
if (options.rateLimit) {
decorators.push(rateLimit(options.rateLimit.requests, options.rateLimit.window));
}
return createCompositeDecorator(...decorators);
};
/**
* 技能2: 装饰器元数据管理
*/
class MetadataManager {
static getClassMetadata(target: any) {
return {
routes: this.getRoutes(target),
inputs: Reflect.getMetadata('component:inputs', target) || [],
outputs: Reflect.getMetadata('component:outputs', target) || [],
hooks: Reflect.getMetadata('component:hooks', target) || {}
};
}
static getRoutes(target: any) {
const routes: any[] = [];
const prototype = target.prototype;
Object.getOwnPropertyNames(prototype).forEach(key => {
if (key !== 'constructor') {
const path = Reflect.getMetadata('api:path', prototype, key);
const method = Reflect.getMetadata('api:method', prototype, key);
if (path && method) {
routes.push({ method: key, path, httpMethod: method });
}
}
});
return routes;
}
}
/**
* 技能3: 装饰器错误处理
*/
function safeDecorator(decoratorFn: Function) {
return function(...args: any[]) {
try {
return decoratorFn(...args);
} catch (error) {
console.warn('装饰器执行失败:', error);
// 返回空装饰器,不影响原有功能
return function(target: any, key?: string, descriptor?: PropertyDescriptor) {
return descriptor;
};
}
};
}
console.log('=== 实用技能演示 ===');
// "=== 实用技能演示 ==="
class AdvancedController {
@createApiEndpoint('/api/users', 'GET', {
cache: 30000,
rateLimit: { requests: 10, window: 60000 }
})
getUsers(request: any) {
return { users: [] };
}
@createApiEndpoint('/api/users', 'POST', {
auth: ['admin'],
rateLimit: { requests: 5, window: 60000 }
})
createUser(request: any) {
return { success: true };
}
}
// 获取类的完整元数据
const metadata = MetadataManager.getClassMetadata(AdvancedController);
console.log('控制器元数据:', metadata);
// "控制器元数据: {routes: [{method: 'getUsers', path: '/api/users', httpMethod: 'GET'}, {method: 'createUser', path: '/api/users', httpMethod: 'POST'}], inputs: [], outputs: [], hooks: {}}"
🎯 设计模式应用
模式 |
装饰器实现 |
应用场景 |
AOP切面 |
方法拦截装饰器 |
日志、监控、事务 |
代理模式 |
类装饰器 |
访问控制、懒加载 |
观察者模式 |
属性装饰器 |
数据绑定、事件 |
工厂模式 |
装饰器工厂 |
配置化创建 |
策略模式 |
参数装饰器 |
算法选择 |
🌟 最佳实践总结
-
保持简单: 每个装饰器只做一件事
-
可配置: 使用工厂函数提供灵活配置
-
可组合: 设计时考虑装饰器的组合使用
-
错误处理: 装饰器失败不应影响核心功能
-
性能考虑: 避免在装饰器中进行重复计算
-
类型安全: 充分利用TypeScript的类型系统
-
文档完善: 为装饰器提供清晰的使用说明
🚀 进阶学习方向
-
反射元数据: 深入学习
reflect-metadata
库
-
编译时装饰器: 了解装饰器的编译过程
-
框架源码: 研究Vue、NestJS等框架的装饰器实现
-
自定义装饰器库: 构建可复用的装饰器工具库
-
性能优化: 装饰器的性能优化技巧
-
测试策略: 装饰器的单元测试方法
🎉 恭喜你! 你已经掌握了TypeScript装饰器这个强大的元编程工具。装饰器就像是代码世界的"魔法装甲",能够在不改变原有代码结构的情况下,为你的类、方法和属性赋予各种神奇的能力。
从基础的方法监控到复杂的API管理系统,从简单的属性验证到完整的依赖注入框架,装饰器为我们提供了一种优雅、可维护的代码增强方式。
记住:好的装饰器应该像隐形的助手,默默地增强你的代码,而不是喧宾夺主。 在实际项目中,合理使用装饰器能够让你的代码更加简洁、可维护,并且具有更好的可扩展性。
继续探索TypeScript的更多高级特性,让你的代码变得更加强大和优雅! 🚀✨