深入解析装饰器模式(Decorator Pattern)
一、装饰器模式的核心概念
装饰器模式是一种结构型设计模式 ,用于动态地给对象添加新功能 ,而不改变其原始代码。
1. 为什么需要装饰器?
- 避免继承带来的类爆炸问题:如果每种新功能都创建子类,组合复杂时类会爆炸式增长。
- 支持动态扩展功能 :继承是静态 的,而装饰器可以在运行时动态添加/移除功能。
- 遵循开闭原则(OCP) :不修改原始代码,而是通过装饰器增强。
二、装饰器的核心机制
装饰器本质上就是一个高阶函数 ,它接收一个函数(或类)作为参数,返回一个新的函数(或类) ,增强原有功能。
装饰器的执行顺序
-
定义装饰器
- 编写一个函数 ,接收原函数
func
,在wrapper
中增加新功能。
- 编写一个函数 ,接收原函数
-
应用装饰器
- 通过
@decorator
语法,把装饰器作用在目标函数上。
- 通过
-
调用目标函数
- 实际执行的是
wrapper()
,它先执行装饰逻辑,再调用原函数。
- 实际执行的是
三、Python 装饰器示例
1. 计时装饰器
📌 示例:在函数运行前后打印执行时间
python
import time
# 定义装饰器
def time_logger(func):
def wrapper(*args, **kwargs):
start_time = time.time() # 记录开始时间
result = func(*args, **kwargs) # 执行原函数
end_time = time.time() # 记录结束时间
print(f"{func.__name__} 执行时间: {end_time - start_time:.6f} 秒")
return result # 返回原函数的返回值
return wrapper # 返回包装后的函数
# 使用装饰器
@time_logger
def slow_function():
time.sleep(1)
print("函数执行完毕")
slow_function()
执行流程:
-
@time_logger
作用在slow_function
上,相当于slow_function = time_logger(slow_function)
。 -
当调用
slow_function()
时,实际上执行的是wrapper()
:- 先 记录时间
start_time
。 - 再 调用
slow_function()
。 - 最后 计算并打印执行时间。
- 先 记录时间
输出示例:
函数执行完毕
slow_function 执行时间: 1.000123 秒
2. 日志装饰器
📌 示例:在函数执行前后自动记录日志
python
def log_decorator(func):
def wrapper(*args, **kwargs):
print(f"开始执行 {func.__name__},参数:{args} {kwargs}")
result = func(*args, **kwargs)
print(f"{func.__name__} 执行完毕,返回值:{result}")
return result
return wrapper
@log_decorator
def add(a, b):
return a + b
print(add(3, 5))
执行流程:
-
@log_decorator
把add
包装成wrapper
,add
变成wrapper
的引用。 -
当
add(3, 5)
执行时:- 先 打印
"开始执行 add,参数:(3, 5) {}"
- 再 运行
add(3, 5)
- 最后 记录
"add 执行完毕,返回值:8"
- 先 打印
输出示例:
csharp
开始执行 add,参数:(3, 5) {}
add 执行完毕,返回值:8
8
3. 组合多个装饰器
装饰器可以层层叠加,按顺序执行:
python
@time_logger
@log_decorator
def multiply(a, b):
time.sleep(0.5)
return a * b
print(multiply(2, 3))
执行流程:
- 先 执行
log_decorator
- 再 执行
time_logger
- 最后 执行
multiply
输出示例:
python
开始执行 multiply,参数:(2, 3) {}
函数执行完毕
multiply 执行时间: 0.500123 秒
multiply 执行完毕,返回值:6
6
四、JavaScript 装饰器示例
1. 计时装饰器
python
function timeLogger(func) {
return function (...args) {
const startTime = Date.now();
const result = func(...args); // 执行原函数
const endTime = Date.now();
console.log(`${func.name} 执行时间: ${(endTime - startTime) / 1000} 秒`);
return result;
};
}
function slowFunction() {
console.log("函数执行中...");
for (let i = 0; i < 1e9; i++) {} // 模拟耗时操作
console.log("函数执行完毕");
}
const wrappedFunction = timeLogger(slowFunction);
wrappedFunction();
执行流程:
-
timeLogger(slowFunction)
返回wrapper
,wrappedFunction
变成wrapper
。 -
执行
wrappedFunction()
时:- 先 记录
startTime
。 - 再 执行
slowFunction()
。 - 最后 计算执行时间并打印。
- 先 记录
输出示例:
python
函数执行中...
函数执行完毕
slowFunction 执行时间: 2.345 秒
2. ES7+ 修饰器(Decorator)
在现代 JavaScript 中,可以使用 @decorator
语法:
python
function logDecorator(target, key, descriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args) {
console.log(`执行 ${key},参数:`, args);
const result = originalMethod.apply(this, args);
console.log(`返回值:`, result);
return result;
};
return descriptor;
}
class MathOperations {
@logDecorator
add(a, b) {
return a + b;
}
}
const math = new MathOperations();
math.add(3, 5);
输出示例:
python
执行 add,参数:[3, 5]
返回值:8
五、装饰器模式 vs 代理模式
对比项 | 装饰器模式(Decorator) | 代理模式(Proxy) |
---|---|---|
作用 | 增强对象功能 | 控制对象访问 |
是否修改原对象 | ❌ 不修改 | ❌ 只代理,通常不修改 |
是否拦截请求 | ❌ 不拦截 | ✅ 代理可拦截请求 |
典型应用 | Vue reactive() 、日志、计时 |
API 代理、缓存、权限控制 |
六、总结
- 装饰器模式用于动态扩展对象功能,而不修改其原始代码。
- 装饰器本质是一个高阶函数,接收函数/类作为参数,返回一个增强版本。
- Python
@decorator
语法糖让装饰器更直观 ,JavaScript 也可以使用@decorator
(ES7+)。 - 适用于日志记录、权限控制、缓存优化等场景。
🚀 掌握装饰器模式,让你的代码更优雅、更灵活!