装饰器模式(C++python)
这段代码是装饰器模式(Decorator Pattern) 的经典实现,用于动态地给对象添加额外功能,同时不改变其原始结构。下面从代码结构、执行流程两方面详细讲解:
一、代码结构解析(装饰器模式核心角色)
装饰器模式包含4个核心角色,这段代码完整实现了这些角色:
1. 抽象构件(Component):Shape
类
class Shape
{
public:virtual void draw() = 0; // 纯虚函数,定义核心功能(绘制)virtual ~Shape() {} // 虚析构函数,确保子类析构正常
};
- 作用:定义所有具体构件和装饰器的统一接口(
draw()
方法),是装饰器模式的基础。
2. 具体构件(Concrete Component):Circle
类
class Circle : public Shape
{
public:void draw() override{std::cout << "Drawing a circle" << std::endl; // 实现具体绘制逻辑}
};
- 作用:实现抽象构件的具体对象(这里是“圆形”),是被装饰的原始对象。
3. 抽象装饰器(Decorator):ShapeDecorator
类
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
// 给形状添加红色边框
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
函数详解)
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)是一种特殊的语法结构,用于动态地给函数或类添加额外功能,而无需修改其原始代码。它本质上是一个“包装函数”,可以在不侵入原函数的前提下,增强其功能。
一、装饰器的核心思想
装饰器基于 “开闭原则”:对扩展开放(可以新增功能),对修改关闭(不改变原有代码)。
例如,你写了一个计算函数,现在需要给它添加“计算耗时”“日志记录”“参数校验”等功能,装饰器就是最佳选择。
二、装饰器的基本语法
装饰器通过 @装饰器名
的语法糖应用在函数或类上,示例:
# 定义一个装饰器
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
接收任意参数,确保兼容性:
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 + badd(3, 5) # 调用被装饰的函数
输出结果:
调用函数:add,参数:(3, 5), {}
函数返回值:8
五、带参数的装饰器
装饰器本身也可以接受参数,用于动态调整装饰逻辑。实现方式是“装饰器工厂”(在装饰器外层再包一层函数):
def repeat(num): # 装饰器的参数def decorator(func):def wrapper(*args, **kwargs):for _ in range(num): # 使用装饰器的参数result = func(*args, **kwargs)return resultreturn wrapperreturn decorator@repeat(num=3) # 给装饰器传参
def say_hello(name):print(f"Hello, {name}!")say_hello("Python")
输出结果:
Hello, Python!
Hello, Python!
Hello, 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 = nameobj = MyClass("测试类")
print(obj.extra_method()) # 调用被装饰器添加的方法
输出结果:
我是测试类的新方法
七、保留原函数信息
装饰器会默认覆盖原函数的元信息(如 __name__
、__doc__
),需要用 functools.wraps
修复:
import functoolsdef my_decorator(func):@functools.wraps(func) # 保留原函数信息def wrapper(*args, **kwargs):return func(*args, **kwargs)return wrapper@my_decorator
def test():"""这是原函数的文档字符串"""passprint(test.__name__) # 输出:test(如果没有wraps,会输出wrapper)
print(test.__doc__) # 输出:这是原函数的文档字符串
八、常见应用场景
- 日志记录:自动记录函数调用时间、参数、返回值。
- 性能测试:计算函数执行耗时。
- 权限验证:在函数执行前检查用户权限。
- 缓存机制:缓存函数的计算结果,避免重复计算。
- 输入验证:检查函数参数是否符合要求。
总结
- 装饰器是 Python 中一种强大的代码复用机制,通过“包装”实现功能扩展。
- 核心语法是
@装饰器名
,本质是函数嵌套和闭包的应用。 - 灵活支持带参数的函数、带参数的装饰器,以及类装饰器。
- 实际开发中,合理使用装饰器可以大幅提高代码的可读性和可维护性。