装饰器模式(C++python)

这段代码是装饰器模式(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):RedBorderDecoratorShadowDecorator
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() 时,会触发链式调用,流程如下:

  1. 执行 ShadowDecorator::draw()

    • 先调用父类 ShapeDecorator::draw(),实际会执行其持有的对象(redBorderCircle)的 draw()
  2. 执行 RedBorderDecorator::draw()

    • 先调用父类 ShapeDecorator::draw(),实际会执行其持有的对象(circle)的 draw()
  3. 执行 Circle::draw()

    • 输出 Drawing a circle(原始功能)。
  4. 回到 RedBorderDecorator::draw()

    • 执行自己的额外功能 addRedBorder(),输出 Adding red border
  5. 回到 ShadowDecorator::draw()

    • 执行自己的额外功能 addShadow(),输出 Adding shadow

三、最终输出结果

复制代码
Drawing a circle
Adding red border
Adding shadow

四、装饰器模式的优势

  1. 动态扩展功能 :无需修改原始类(Circle),就能通过装饰器添加新功能(红色边框、阴影)。
  2. 灵活组合:可以按任意顺序组合多个装饰器(例如先加阴影再加边框,只需调换装饰顺序)。
  3. 遵循开闭原则:新增功能时只需添加新的装饰器类,无需修改现有代码。

这段代码通过简单的打印输出模拟了功能扩展,实际开发中可以是更复杂的逻辑(如GUI组件的样式修饰、数据处理的过滤层等)。

其实装饰器的核心就是,每次进行调用是,先调用具体构建的函数,调用过程会一直网上溯源,直到找到根上,然后逐个根据包装先后顺序进行调用,类似反套娃

python中的装饰器原理类似

在 Python 中,装饰器(Decorator)是一种特殊的语法结构,用于动态地给函数或类添加额外功能,而无需修改其原始代码。它本质上是一个"包装函数",可以在不侵入原函数的前提下,增强其功能。

一、装饰器的核心思想

装饰器基于 "开闭原则" :对扩展开放(可以新增功能),对修改关闭(不改变原有代码)。

例如,你写了一个计算函数,现在需要给它添加"计算耗时""日志记录""参数校验"等功能,装饰器就是最佳选择。

二、装饰器的基本语法

装饰器通过 @装饰器名 的语法糖应用在函数或类上,示例:

python 复制代码
# 定义一个装饰器
def my_decorator(func):
    def wrapper():
        print("装饰器添加的功能:执行前")
        func()  # 调用原函数
        print("装饰器添加的功能:执行后")
    return wrapper

# 用装饰器装饰函数
@my_decorator
def target_func():
    print("这是原函数的逻辑")

# 调用被装饰后的函数
target_func()

输出结果

复制代码
装饰器添加的功能:执行前
这是原函数的逻辑
装饰器添加的功能:执行后

三、装饰器的执行原理

  1. 当 Python 解释器遇到 @my_decorator 时,会自动执行 my_decorator(target_func),将原函数 target_func 作为参数传入装饰器。
  2. 装饰器返回内部的 wrapper 函数,此时 target_func 这个变量名实际上指向了 wrapper 函数。
  3. 因此,调用 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__)   # 输出:这是原函数的文档字符串

八、常见应用场景

  1. 日志记录:自动记录函数调用时间、参数、返回值。
  2. 性能测试:计算函数执行耗时。
  3. 权限验证:在函数执行前检查用户权限。
  4. 缓存机制:缓存函数的计算结果,避免重复计算。
  5. 输入验证:检查函数参数是否符合要求。

总结

  • 装饰器是 Python 中一种强大的代码复用机制,通过"包装"实现功能扩展。
  • 核心语法是 @装饰器名,本质是函数嵌套和闭包的应用。
  • 灵活支持带参数的函数、带参数的装饰器,以及类装饰器。
  • 实际开发中,合理使用装饰器可以大幅提高代码的可读性和可维护性。