这段代码是装饰器模式(Decorator Pattern) 的经典实现,用于动态地给对象添加额外功能,同时不改变其原始结构。下面从代码结构、执行流程两方面详细讲解:

一、代码结构解析(装饰器模式核心角色)
装饰器模式包含4个核心角色,这段代码完整实现了这些角色:
1. 抽象构件(Component):Shape
类
cpp
class Shape
{
public:
virtual void draw() = 0; // 纯虚函数,定义核心功能(绘制)
virtual ~Shape() {} // 虚析构函数,确保子类析构正常
};
- 作用:定义所有具体构件和装饰器的统一接口(
draw()
方法),是装饰器模式的基础。
2. 具体构件(Concrete Component):Circle
类
cpp
class Circle : public Shape
{
public:
void draw() override
{
std::cout << "Drawing a circle" << std::endl; // 实现具体绘制逻辑
}
};
- 作用:实现抽象构件的具体对象(这里是"圆形"),是被装饰的原始对象。
3. 抽象装饰器(Decorator):ShapeDecorator
类
cpp
class ShapeDecorator : public Shape
{
protected:
Shape* decoratedShape; // 持有一个抽象构件的指针(被装饰的对象)
public:
ShapeDecorator(Shape* shape) : decoratedShape(shape) {} // 初始化被装饰对象
void draw() override
{
if (decoratedShape)
{
decoratedShape->draw(); // 调用被装饰对象的原始方法
}
}
};
- 作用:继承自抽象构件(确保接口一致性),同时持有一个被装饰对象的指针,是所有具体装饰器的基类。
4. 具体装饰器(Concrete Decorator):RedBorderDecorator
和 ShadowDecorator
cpp
// 给形状添加红色边框
class RedBorderDecorator : public ShapeDecorator
{
public:
RedBorderDecorator(Shape* shape) : ShapeDecorator(shape) {}
void draw() override
{
ShapeDecorator::draw(); // 先调用被装饰对象的draw()
addRedBorder(); // 再添加额外功能(红色边框)
}
private:
void addRedBorder() { std::cout << "Adding red border" << std::endl; }
};
// 给形状添加阴影
class ShadowDecorator : public ShapeDecorator
{
public:
ShadowDecorator(Shape* shape) : ShapeDecorator(shape) {}
void draw() override
{
ShapeDecorator::draw(); // 先调用被装饰对象的draw()
addShadow(); // 再添加额外功能(阴影)
}
private:
void addShadow() { std::cout << "Adding shadow" << std::endl; }
};
- 作用:继承自抽象装饰器,在重写的
draw()
方法中,先调用被装饰对象的原始方法,再添加自己的额外功能。
二、执行流程(main
函数详解)
cpp
int main()
{
// 1. 创建原始对象:一个圆形(具体构件)
Shape* circle = new Circle();
// 2. 第一次装饰:给圆形添加红色边框
// 注意:RedBorderDecorator接收的是Shape*类型(这里是circle)
Shape* redBorderCircle = new RedBorderDecorator(circle);
// 3. 第二次装饰:给"带红色边框的圆形"再添加阴影
// 注意:ShadowDecorator接收的是Shape*类型(这里是已装饰过的redBorderCircle)
Shape* decoratedCircle = new ShadowDecorator(redBorderCircle);
// 4. 调用最终装饰对象的draw()方法
decoratedCircle->draw();
// 5. 释放内存(按创建顺序的逆序释放,避免悬空指针)
delete decoratedCircle; // 先释放最外层装饰
delete redBorderCircle; // 再释放中间层装饰
delete circle; // 最后释放原始对象
char t;
std::cin >> t; // 暂停程序,方便查看输出
return 0;
}
关键步骤:decoratedCircle->draw()
的执行过程
当调用最终装饰对象的 draw()
时,会触发链式调用,流程如下:
-
执行
ShadowDecorator::draw()
:- 先调用父类
ShapeDecorator::draw()
,实际会执行其持有的对象(redBorderCircle
)的draw()
。
- 先调用父类
-
执行
RedBorderDecorator::draw()
:- 先调用父类
ShapeDecorator::draw()
,实际会执行其持有的对象(circle
)的draw()
。
- 先调用父类
-
执行
Circle::draw()
:- 输出
Drawing a circle
(原始功能)。
- 输出
-
回到
RedBorderDecorator::draw()
:- 执行自己的额外功能
addRedBorder()
,输出Adding red border
。
- 执行自己的额外功能
-
回到
ShadowDecorator::draw()
:- 执行自己的额外功能
addShadow()
,输出Adding shadow
。
- 执行自己的额外功能
三、最终输出结果
Drawing a circle
Adding red border
Adding shadow
四、装饰器模式的优势
- 动态扩展功能 :无需修改原始类(
Circle
),就能通过装饰器添加新功能(红色边框、阴影)。 - 灵活组合:可以按任意顺序组合多个装饰器(例如先加阴影再加边框,只需调换装饰顺序)。
- 遵循开闭原则:新增功能时只需添加新的装饰器类,无需修改现有代码。
这段代码通过简单的打印输出模拟了功能扩展,实际开发中可以是更复杂的逻辑(如GUI组件的样式修饰、数据处理的过滤层等)。
其实装饰器的核心就是,每次进行调用是,先调用具体构建的函数,调用过程会一直网上溯源,直到找到根上,然后逐个根据包装先后顺序进行调用,类似反套娃
python中的装饰器原理类似
在 Python 中,装饰器(Decorator)是一种特殊的语法结构,用于动态地给函数或类添加额外功能,而无需修改其原始代码。它本质上是一个"包装函数",可以在不侵入原函数的前提下,增强其功能。
一、装饰器的核心思想
装饰器基于 "开闭原则" :对扩展开放(可以新增功能),对修改关闭(不改变原有代码)。
例如,你写了一个计算函数,现在需要给它添加"计算耗时""日志记录""参数校验"等功能,装饰器就是最佳选择。
二、装饰器的基本语法
装饰器通过 @装饰器名
的语法糖应用在函数或类上,示例:
python
# 定义一个装饰器
def my_decorator(func):
def wrapper():
print("装饰器添加的功能:执行前")
func() # 调用原函数
print("装饰器添加的功能:执行后")
return wrapper
# 用装饰器装饰函数
@my_decorator
def target_func():
print("这是原函数的逻辑")
# 调用被装饰后的函数
target_func()
输出结果:
装饰器添加的功能:执行前
这是原函数的逻辑
装饰器添加的功能:执行后
三、装饰器的执行原理
- 当 Python 解释器遇到
@my_decorator
时,会自动执行my_decorator(target_func)
,将原函数target_func
作为参数传入装饰器。 - 装饰器返回内部的
wrapper
函数,此时target_func
这个变量名实际上指向了wrapper
函数。 - 因此,调用
target_func()
时,实际执行的是wrapper()
函数,从而实现了"在原函数前后添加功能"的效果。
四、带参数的函数如何装饰?
如果原函数有参数,装饰器的 wrapper
函数需要用 *args
和 **kwargs
接收任意参数,确保兼容性:
python
def log_decorator(func):
def wrapper(*args, **kwargs):
print(f"调用函数:{func.__name__},参数:{args}, {kwargs}")
result = func(*args, **kwargs) # 传递参数给原函数
print(f"函数返回值:{result}")
return result # 返回原函数的结果
return wrapper
@log_decorator
def add(a, b):
return a + b
add(3, 5) # 调用被装饰的函数
输出结果:
调用函数:add,参数:(3, 5), {}
函数返回值:8
五、带参数的装饰器
装饰器本身也可以接受参数,用于动态调整装饰逻辑。实现方式是"装饰器工厂"(在装饰器外层再包一层函数):
python
def repeat(num): # 装饰器的参数
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(num): # 使用装饰器的参数
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(num=3) # 给装饰器传参
def say_hello(name):
print(f"Hello, {name}!")
say_hello("Python")
输出结果:
Hello, Python!
Hello, Python!
Hello, Python!
六、类装饰器
除了装饰函数,装饰器也可以装饰类,用于增强类的功能(如添加方法、属性等):
python
def add_method(cls):
# 给类添加一个新方法
def new_method(self):
return f"我是{self.name}的新方法"
cls.extra_method = new_method # 动态绑定方法
return cls
@add_method
class MyClass:
def __init__(self, name):
self.name = name
obj = MyClass("测试类")
print(obj.extra_method()) # 调用被装饰器添加的方法
输出结果:
我是测试类的新方法
七、保留原函数信息
装饰器会默认覆盖原函数的元信息(如 __name__
、__doc__
),需要用 functools.wraps
修复:
python
import functools
def my_decorator(func):
@functools.wraps(func) # 保留原函数信息
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@my_decorator
def test():
"""这是原函数的文档字符串"""
pass
print(test.__name__) # 输出:test(如果没有wraps,会输出wrapper)
print(test.__doc__) # 输出:这是原函数的文档字符串
八、常见应用场景
- 日志记录:自动记录函数调用时间、参数、返回值。
- 性能测试:计算函数执行耗时。
- 权限验证:在函数执行前检查用户权限。
- 缓存机制:缓存函数的计算结果,避免重复计算。
- 输入验证:检查函数参数是否符合要求。
总结
- 装饰器是 Python 中一种强大的代码复用机制,通过"包装"实现功能扩展。
- 核心语法是
@装饰器名
,本质是函数嵌套和闭包的应用。 - 灵活支持带参数的函数、带参数的装饰器,以及类装饰器。
- 实际开发中,合理使用装饰器可以大幅提高代码的可读性和可维护性。