装饰器模式
High Contrast
Dark Mode
Light Mode
Sepia
Forest
3 min read567 words

装饰器模式

装饰器模式(Decorator Pattern)动态地给一个对象添加一些额外的职责,就增加功能来说,装饰器模式比生成子类更为灵活。

问题定义

场景1:咖啡订单系统

# ❌ 问题:继承爆炸
class Coffee:
def cost(self):
return 5
class MilkCoffee(Coffee):
def cost(self):
return super().cost() + 2
class SugarCoffee(MilkCoffee):
def cost(self):
return super().cost() + 1
class WhippedCreamCoffee(SugarCoffee):
def cost(self):
return super().cost() + 3
# 问题:需要所有组合的子类
# Coffee, MilkCoffee, SugarCoffee, WhippedCreamCoffee,
# MilkSugarCoffee, MilkWhippedCoffee, SugarWhippedCoffee,
# MilkSugarWhippedCoffee... 2^n种组合!

场景2:文本处理

# ❌ 问题:静态继承,无法动态组合
class Text:
def get_text(self):
return "Hello"
def render(self):
return self.get_text()
class BoldText(Text):
def render(self):
return f"<b>{super().render()}</b>"
class ItalicText(Text):
def render(self):
return f"<i>{super().render()}</i>"
# 问题:想要同时加粗和斜体怎么办?
# 需要创建BoldItalicText,UnderlinedBoldText等无数组合

解决方案

装饰器模式使用组合而非继承,动态地添加功能。

classDiagram class Component { <> +operation() } class ConcreteComponent { +operation() } class Decorator { -component: Component +operation() } class ConcreteDecoratorA { +operation() +addedBehavior() } class ConcreteDecoratorB { +operation() +addedBehavior() } Component <|-- ConcreteComponent Component <|-- Decorator Decorator <|-- ConcreteDecoratorA Decorator <|-- ConcreteDecoratorB Decorator o-- Component : wraps

标准实现

组件接口

from abc import ABC, abstractmethod
class Coffee(ABC):
"""咖啡抽象类"""
@abstractmethod
def cost(self):
pass
@abstractmethod
def description(self):
pass

具体组件

class SimpleCoffee(Coffee):
"""简单咖啡"""
def cost(self):
return 5.0
def description(self):
return "简单咖啡"

装饰器基类

class CoffeeDecorator(Coffee):
"""咖啡装饰器基类"""
def __init__(self, coffee: Coffee):
self._coffee = coffee
def cost(self):
return self._coffee.cost()
def description(self):
return self._coffee.description()

具体装饰器

class MilkDecorator(CoffeeDecorator):
"""牛奶装饰器"""
def cost(self):
return self._coffee.cost() + 2.0
def description(self):
return f"{self._coffee.description()}, 牛奶"
class SugarDecorator(CoffeeDecorator):
"""糖装饰器"""
def cost(self):
return self._coffee.cost() + 1.0
def description(self):
return f"{self._coffee.description()}, 糖"
class WhippedCreamDecorator(CoffeeDecorator):
"""奶油装饰器"""
def cost(self):
return self._coffee.cost() + 3.0
def description(self):
return f"{self._coffee.description()}, 奶油"
class VanillaDecorator(CoffeeDecorator):
"""香草装饰器"""
def cost(self):
return self._coffee.cost() + 1.5
def description(self):
return f"{self._coffee.description()}, 香草"

客户端使用

# 简单咖啡
coffee1 = SimpleCoffee()
print(f"{coffee1.description()}: ${coffee1.cost()}")
# 简单咖啡: $5.0
# 加牛奶的咖啡
coffee2 = MilkDecorator(SimpleCoffee())
print(f"{coffee2.description()}: ${coffee2.cost()}")
# 简单咖啡, 牛奶: $7.0
# 加牛奶和糖的咖啡
coffee3 = SugarDecorator(MilkDecorator(SimpleCoffee()))
print(f"{coffee3.description()}: ${coffee3.cost()}")
# 简单咖啡, 牛奶, 糖: $8.0
# 完全自定义:加牛奶、糖、奶油、香草
coffee4 = VanillaDecorator(
WhippedCreamDecorator(
SugarDecorator(
MilkDecorator(SimpleCoffee())
)
)
)
print(f"{coffee4.description()}: ${coffee4.cost()}")
# 简单咖啡, 牛奶, 糖, 奶油, 香草: $12.5

Python装饰器语法

Python 的 @decorator 语法是装饰器模式的完美实现:

def log_calls(func):
"""日志装饰器"""
def wrapper(*args, **kwargs):
print(f"调用 {func.__name__}")
result = func(*args, **kwargs)
print(f"{func.__name__} 返回: {result}")
return result
return wrapper
@log_calls
def add(x, y):
"""加法函数"""
return x + y
# 等价于 add = log_calls(add)
result = add(3, 5)
# 调用 add
# add 返回: 8
print(f"结果: {result}")

带参数的装饰器

def repeat(times):
"""重复执行装饰器"""
def decorator(func):
def wrapper(*args, **kwargs):
results = []
for _ in range(times):
result = func(*args, **kwargs)
results.append(result)
return results
return wrapper
return decorator
@repeat(times=3)
def greet(name):
return f"Hello, {name}!"
print(greet("Alice"))
# ['Hello, Alice!', 'Hello, Alice!', 'Hello, Alice!']

实战应用

应用1:文本格式化

from abc import ABC, abstractmethod
class Text(ABC):
"""文本抽象类"""
@abstractmethod
def render(self):
pass
class PlainText(Text):
"""纯文本"""
def __init__(self, text):
self.text = text
def render(self):
return self.text
class BoldDecorator(Text):
"""粗体装饰器"""
def __init__(self, text: Text):
self._text = text
def render(self):
return f"<b>{self._text.render()}</b>"
class ItalicDecorator(Text):
"""斜体装饰器"""
def __init__(self, text: Text):
self._text = text
def render(self):
return f"<i>{self._text.render()}</i>"
class UnderlineDecorator(Text):
"""下划线装饰器"""
def __init__(self, text: Text):
self._text = text
def render(self):
return f"<u>{self._text.render()}</u>"
class ColorDecorator(Text):
"""颜色装饰器"""
def __init__(self, text: Text, color):
self._text = text
self.color = color
def render(self):
return f'<span style="color:{self.color}">{self._text.render()}</span>'
# 使用
text1 = BoldDecorator(PlainText("Hello"))
print(text1.render())
# <b>Hello</b>
text2 = ItalicDecorator(BoldDecorator(PlainText("World")))
print(text2.render())
# <i><b>World</b></i>
text3 = ColorDecorator(
UnderlineDecorator(
ItalicDecorator(PlainText("Python"))
),
"red"
)
print(text3.render())
# <span style="color:red"><u><i>Python</i></u></span>

应用2:函数计时

import time
from functools import wraps
def timing_decorator(func):
"""计时装饰器"""
@wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
elapsed = end_time - start_time
print(f"{func.__name__} 执行时间: {elapsed:.4f}秒")
return result
return wrapper
@timing_decorator
def slow_function():
"""慢函数"""
time.sleep(1)
return "完成"
@timing_decorator
def fast_function():
"""快函数"""
return "完成"
slow_function()
# slow_function 执行时间: 1.0012秒
fast_function()
# fast_function 执行时间: 0.0001秒

应用3:权限检查

class PermissionDecorator:
"""权限装饰器"""
def __init__(self, func, required_permission):
self.func = func
self.required_permission = required_permission
def __call__(self, *args, **kwargs):
if not self._check_permission():
raise PermissionError("权限不足")
return self.func(*args, **kwargs)
def _check_permission(self):
"""检查权限(简化版)"""
# 实际应用中会检查用户权限
return True
# 装饰器工厂
def require_permission(permission):
"""需要特定权限"""
def decorator(func):
return PermissionDecorator(func, permission)
return decorator
# 使用
class Document:
"""文档管理"""
@require_permission("read")
def read(self, doc_id):
return f"读取文档 {doc_id}"
@require_permission("write")
def write(self, doc_id, content):
return f"写入文档 {doc_id}: {content}"
@require_permission("admin")
def delete(self, doc_id):
return f"删除文档 {doc_id}"
# 实际使用
doc = Document()
print(doc.read(1))
print(doc.write(1, "内容"))
print(doc.delete(1))

应用4:缓存

from functools import wraps
import json
def cache_decorator(func):
"""缓存装饰器"""
cache = {}
@wraps(func)
def wrapper(*args, **kwargs):
# 生成缓存键
key = f"{func.__name__}:{args}:{kwargs}"
if key in cache:
print("从缓存读取")
return cache[key]
# 调用原函数
result = func(*args, **kwargs)
cache[key] = result
print("计算并缓存")
return result
return wrapper
@cache_decorator
def expensive_computation(x, y):
"""昂贵的计算"""
print("执行计算...")
return x ** y
# 第一次调用:计算并缓存
result1 = expensive_computation(2, 10)
# 执行计算...
# 计算并缓存
# 第二次调用:从缓存读取
result2 = expensive_computation(2, 10)
# 从缓存读取
print(result1 == result2)  # True

装饰器组合

装饰器可以堆叠使用:

def log(func):
"""日志装饰器"""
@wraps(func)
def wrapper(*args, **kwargs):
print(f"[LOG] 调用 {func.__name__}")
return func(*args, **kwargs)
return wrapper
def auth(func):
"""认证装饰器"""
@wraps(func)
def wrapper(*args, **kwargs):
print(f"[AUTH] 验证权限")
return func(*args, **kwargs)
return wrapper
def timing(func):
"""计时装饰器"""
@wraps(func)
def wrapper(*args, **kwargs):
print(f"[TIMING] 开始计时")
return func(*args, **kwargs)
return wrapper
# 装饰器堆叠 - 从下到上执行
@log
@auth
@timing
def process_data(data):
"""处理数据"""
print(f"处理数据: {data}")
return "完成"
# 等价于 process_data = log(auth(timing(process_data)))
result = process_data("test")
# [LOG] 调用 process_data
# [AUTH] 验证权限
# [TIMING] 开始计时
# 处理数据: test

装饰器顺序

装饰器的执行顺序很重要:

def decorator_a(func):
print("装饰器A 被调用")
def wrapper():
print("装饰器A - 前")
func()
print("装饰器A - 后")
return wrapper
def decorator_b(func):
print("装饰器B 被调用")
def wrapper():
print("装饰器B - 前")
func()
print("装饰器B - 后")
return wrapper
# 装饰顺序:B -> A
@decorator_a
@decorator_b
def my_function():
print("函数执行")
print("定义函数时:")
# 装饰器B 被调用
# 装饰器A 被调用
print("\n调用函数时:")
my_function()
# 装饰器A - 前
# 装饰器B - 前
# 函数执行
# 装饰器B - 后
# 装饰器A - 后

装饰器 vs 继承

特性 装饰器模式 继承
灵活性 高 - 运行时动态组合 低 - 编译时静态定义
类数量 少 - 组合即可 多 - 每个组合一个子类
扩展性 好 - 添加新装饰器 差 - 需要新子类
复杂度 中等 简单但扩展困难
graph TB A[扩展方式] --> B[装饰器模式] A --> C[继承] B --> B1[运行时动态组合] B --> B2[装饰器可复用] B --> B3[类数量少] C --> C1[编译时静态定义] C --> C2[每个组合一个子类] C --> C3[类数量爆炸] style A fill:#ede7f6,stroke:#5e35b1,stroke-width:3px style B fill:#e3f2fd,stroke:#1976d2,stroke-width:2px style C fill:#ffcdd2,stroke:#c62828,stroke-width:2px

优缺点

✅ 优点

优点 说明
动态扩展 运行时添加功能
灵活组合 自由组合装饰器
单一职责 每个装饰器只负责一个功能
避免继承爆炸 不需要所有组合的子类

❌ 缺点

缺点 说明
复杂度 多层装饰器难以调试
性能 多层调用开销
小对象过多 每个装饰器都是小对象

Python装饰器 vs GoF装饰器

维度 GoF装饰器 Python装饰器
语法 类装饰器 函数装饰器
实现 继承 + 组合 函数闭包
使用场景 对象装饰 函数/类装饰
Python特色 - @decorator 语法

本章要点


下一步代理模式 🚀