【第八节】C++设计模式(结构型模式)-Decorator(装饰器)模式

发布于:2025-02-27 ⋅ 阅读:(8) ⋅ 点赞:(0)

目录

一、问题引出

二、模式选择

三、代码实现

四、总结讨论


一、问题引出

        装饰器模式:动态扩展对象功能的设计模式

        在面向对象(OO)设计与开发中,我们常面临为已有类添加新职责的需求。传统方法是通过继承创建子类来实现功能扩展,但这种方式容易导致继承层次过深,显著增加系统复杂度。装饰器模式(Decorator Pattern)应运而生,其通过组合替代继承的机制,为功能扩展提供了更灵活的解决方案,从而避免了继承层次过深带来的复杂性。

二、模式选择

装饰器模式的典型结构图如下:

        在结构中,ConcreteComponent(具体组件)和 Decorator(装饰器)均继承自 Component 基类,共享统一接口。可能有人质疑:为何不直接让 Decorator 持有 ConcreteComponent 的指针来实现扩展?答案是此方式仅支持单一组件类型。若新增其他组件类型(如 AnotherConcreteComponent),则需重新定义新的装饰器类,违背开闭原则。而通过共享 Component 基类,装饰器可借助多态特性,适配所有子类对象,实现通用扩展能力。这正是装饰器模式的核心优势。

:若仅需为单一组件类型添加功能,可省略 Decorator 基类,直接实现具体装饰器。

三、代码实现

        装饰器模式的实现并不复杂,下面是一个完整的代码示例(采用 C++ 实现)。

代码片段 1:Decorator.h

#ifndef _DECORATOR_H_
#define _DECORATOR_H_

// 抽象组件基类
class Component {
public:
    virtual ~Component() {}
    virtual void Operation() = 0;  // 纯虚接口
protected:
    Component() {}  // 允许子类构造
};

// 具体组件类
class ConcreteComponent : public Component {
public:
    void Operation() override;  // 实现基类接口
};

// 抽象装饰器基类
class Decorator : public Component {
public:
    Decorator(Component* com) : _com(com) {}
    virtual ~Decorator() { delete _com; }  // 管理组件生命周期
    void Operation() override;            // 委托给组件对象
protected:
    Component* _com;  // 组合的组件对象
};

// 具体装饰器类
class ConcreteDecorator : public Decorator {
public:
    ConcreteDecorator(Component* com) : Decorator(com) {}
    void Operation() override;  
    void AddedBehavior();        // 新增扩展行为
};

#endif //~_DECORATOR_H_

代码片段 2:Decorator.cpp

#include "Decorator.h"
#include <iostream>

// 具体组件实现
void ConcreteComponent::Operation() {
    std::cout << "ConcreteComponent: 基础操作" << std::endl;
}

// 装饰器默认实现(可省略)
void Decorator::Operation() {
    if (_com) _com->Operation();  // 委托调用
}

// 具体装饰器扩展实现
void ConcreteDecorator::Operation() {
    Decorator::Operation();      // 调用原有功能
    AddedBehavior();             // 添加新行为
}

void ConcreteDecorator::AddedBehavior() {
    std::cout << "ConcreteDecorator: 新增扩展行为" << std::endl;
}

代码片段 3:main.cpp

#include "Decorator.h"

int main() {
    Component* component = new ConcreteComponent();  // 创建基础组件
    Component* decorated = new ConcreteDecorator(component);  // 动态装饰
    decorated->Operation();  // 执行扩展后的操作

    delete decorated;  // 释放资源(自动递归删除组件)
    return 0;
}

代码解析

组件与装饰器关系

        ConcreteComponent 实现基础功能,ConcreteDecorator 通过组合持有组件对象,并在其操作前后添加新行为。

        装饰器类继承自 Component,保证接口一致性,支持嵌套装饰(如DecoratorA(DecoratorB(Component)))。

生命周期管理

        装饰器负责管理其持有的组件对象(delete _com),客户端仅需释放最外层装饰器,避免内存泄漏。

输出结果
        ConcreteComponent: 基础操作
        ConcreteDecorator: 新增扩展行为

四、总结讨论

模式对比:装饰器 vs 代理 vs 组合

        若装饰器仅持有具体组件(非抽象接口),其结构将与代理模式高度相似,但两者意图截然不同。

        装饰器模式与组合模式(Composite Pattern)在结构上有些相似,但它们的主要区别在于应用场景和目的。装饰器模式与代理模式(Proxy Pattern)在某些方面也有相似之处。虽然它们在结构图上并不相似,但如果让 `Decorator` 直接持有一个 `ConcreteComponent` 的引用(指针),其结构图就与代理模式非常相似了。

        由此,装饰器模式与代理模式的相似之处在于,它们都通过组合的方式持有一个指向其他对象的引用(指针)。不同之处在于,代理模式通常会提供与其代理对象相同的接口,并将操作直接委托给代理对象执行。而装饰器模式则通过组合的方式动态地为对象添加新的职责。

        装饰器模式不仅通过组合的方式避免了继承带来的复杂性,还为设计提供了一种“即用即付”的方式来添加职责。在 OO 设计和分析中,常常会遇到这样的情况:为了多态性,通过父类指针指向其具体子类,但当具体子类需要添加新的职责时,就必须在父类中添加相应的抽象接口。这会导致父类承载过多的职责,并且所有子类都会继承这些接口,即使它们并不需要。装饰器模式通过动态添加职责的方式,很好地解决了这一问题。由此总结其核心优势与适用场景如下:

优势

        (1)动态扩展:运行时灵活添加功能,避免静态继承的臃肿。

        (2)接口一致性:装饰后对象仍为 Component 类型,兼容原有逻辑。

        (3)职责分离:每个装饰器仅关注单一扩展点,符合单一职责原则。

适用场景

        (1)需为对象添加可选或可拆卸功能(如日志、缓存、权限校验)。

        (2)无法通过继承扩展(如 final 类)或继承会导致类爆炸。

        装饰器模式通过组合+委托的机制,实现了对象功能的动态扩展。其核心在于:

        (1)开放-封闭原则:无需修改原有代码,通过新增装饰器扩展功能。

        (2)接口抽象:统一组件与装饰器的接口,支持多态嵌套。

        (3)灵活替代继承:避免深度继承层次,降低系统复杂度。

        该模式尤其适用于框架设计或需要高频扩展的场景,是面向对象设计中“组合优于继承”理念的经典实践。