Python 深入浅出:设计模式中的“装饰器”与 Python “装饰器”的异同
在面向对象编程中,“装饰器”是一个经常引起混淆的词汇。
当开发者阅读经典的《设计模式:可复用面向对象软件的基础》(GoF)一书时,会读到 “装饰器模式(Decorator Pattern)”;而当他们学习 Python 语言时,又会遇到以 @ 符号为代表的 “Python 装饰器(Decorators)”。
这两者虽然名字完全相同,但在概念设计、实现机制以及应用层面上其实有着明显的异同。
本文将带您理清设计模式中的“装饰器”与 Python 语言中的“装饰器”之间的恩怨纠葛。
一、 GoF 设计模式中的“装饰器模式”
1. 核心意图
在不改变原有类结构、也不使用继承的前提下,动态地给一个实例对象添加一些额外的职责(功能)。它是通过组合(Composition)代替继承来实现扩展的经典范式。
2. 结构特征
- 接口一致性:装饰器类和被装饰的组件类必须继承自同一个抽象基类(接口)。
- 嵌套包装:装饰器内部持有一个组件对象的引用,在执行自身逻辑前后,调用被包装对象的方法。
classDiagram
class Component {
<<interface>>
+operation()
}
class ConcreteComponent {
+operation()
}
class Decorator {
-Component component
+operation()
}
class ConcreteDecoratorA {
+operation()
}
Component <|-- ConcreteComponent
Component <|-- Decorator
Decorator o-- Component
Decorator <|-- ConcreteDecoratorA
二、 Python 语言中的“装饰器”
1. 核心意图
Python 中的装饰器是一种语言级别的语法糖。它本质上是一个高阶函数:接受一个可调用对象(函数或类)作为入参,并返回一个新的可调用对象。
2. 结构特征
- 语法糖 @:
@my_decorator只是func = my_decorator(func)的简化写法。 - 定义期生效:Python 装饰器在模块加载、函数被定义时就立即执行并完成了包装,而不是在对象运行时动态包装。
def my_decorator(func):
def wrapper(*args, **kwargs):
print("执行前...")
result = func(*args, **kwargs)
print("执行后...")
return result
return wrapper
@my_decorator
def say_hello():
pass
三、 深度对比:两者的本质异同
我们从三个维度来剖析它们之间的差异:
| 维度 | GoF 装饰器模式 | Python 装饰器 |
|---|---|---|
| 本质属性 | 一种架构设计模式(思想) | 一种语法特性(语法糖) |
| 作用粒度 | 对象级别(Object-level)。只对被包装的某一个特定实例生效,其他同类实例不受影响。 | 定义级别(Definition-level)。对被装饰的函数或类模板整体生效,所有生成的实例全部被改变。 |
| 类型约束 | 极强。包装后对象的类型(接口)必须保持一致,以便多层嵌套。 | 极弱。Python 作为动态语言,装饰器甚至可以返回一个与原函数完全不同类型、不同签名的对象。 |
四、 用 Python 实现 GoF 装饰器模式
在 Python 中,因为其动态性,实现传统的 GoF 装饰器模式非常简单,甚至不需要繁琐的接口声明:
# 1. 基础组件:咖啡
class Coffee:
def get_cost(self):
return 10
def get_ingredients(self):
return "咖啡"
# 2. 装饰器基类(保持接口一致,并持有被包装对象)
class CoffeeDecorator:
def __init__(self, coffee):
self._coffee = coffee
def get_cost(self):
return self._coffee.get_cost()
def get_ingredients(self):
return self._coffee.get_ingredients()
# 3. 具体装饰器:加奶
class MilkDecorator(CoffeeDecorator):
def get_cost(self):
# 基础费用 + 牛奶费用 2 元
return super().get_cost() + 2
def get_ingredients(self):
return super().get_ingredients() + ", 加奶"
# 运行期动态包装单例对象
my_coffee = Coffee()
print(f"{my_coffee.get_ingredients()} 的价格: {my_coffee.get_cost()} 元")
# 动态加上牛奶装饰
my_milk_coffee = MilkDecorator(my_coffee)
print(f"{my_milk_coffee.get_ingredients()} 的价格: {my_milk_coffee.get_cost()} 元")
上面的 MilkDecorator 结构就是经典的 GoF 装饰器模式。它是在运行期,通过把 my_coffee 对象塞入 MilkDecorator 的构造函数中,实现了动态扩展。
五、 总结
- GoF 装饰器模式是一种设计思想,强调在运行期对单个实例对象进行组合式的功能叠加。
- Python 装饰器是一种语法糖,强调在编译/定义期对函数或类模板进行切面注入(AOP)。
- 在 Python 编码中,我们可以用 Python 装饰器(语法糖)来优雅地生成和辅助实现 GoF 装饰器模式,两者相辅相成。
理清这两个概念的异同,能让您在进行面向对象架构设计与 Python 编程时,思路更加清晰,表达更加准确!
本站所有文章、数据、图片均来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。
评论交流 (0)
您尚未登录,请先 登录 后发表评论!



暂无评论
还没有人评论过本文,快来发表你的高见吧!