【C++】装饰模式

发布于:2025-06-26 ⋅ 阅读:(22) ⋅ 点赞:(0)

装饰模式(Decorator Pattern)是一种【结构型】设计模式,它允许向一个现有的对象添加新的功能,同时又不改变其结构。这种模式通过创建一个装饰器类,来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。装饰模式在不使用继承的情况下,实现了对象功能的动态扩展。

一、模式核心概念与结构

装饰模式包含四个核心角色:

  1. 抽象组件(Component):定义对象的接口,可以给这些对象动态地添加职责。
  2. 具体组件(Concrete Component):实现抽象组件接口,定义具体的对象,装饰器可以给它增加额外的职责。
  3. 抽象装饰器(Decorator):继承自抽象组件,并持有一个抽象组件的引用,用于装饰具体组件。
  4. 具体装饰器(Concrete Decorator):实现抽象装饰器的方法,在调用具体组件方法的前后,添加额外的功能。

二、C++ 实现示例:咖啡与配料的装饰

以下是一个经典的装饰模式示例,演示如何动态添加咖啡的配料:

#include <iostream>
#include <string>
#include <memory>

// 抽象组件:饮料
class Beverage {
public:
    virtual ~Beverage() {}
    virtual std::string getDescription() const = 0;
    virtual double cost() const = 0;
};

// 具体组件:浓缩咖啡
class Espresso : public Beverage {
public:
    std::string getDescription() const override {
        return "Espresso";
    }
    
    double cost() const override {
        return 1.99;
    }
};

// 具体组件:黑咖啡
class DarkRoast : public Beverage {
public:
    std::string getDescription() const override {
        return "Dark Roast Coffee";
    }
    
    double cost() const override {
        return 0.99;
    }
};

// 抽象装饰器:配料
class CondimentDecorator : public Beverage {
protected:
    std::shared_ptr<Beverage> beverage;  // 持有被装饰对象的引用

public:
    CondimentDecorator(std::shared_ptr<Beverage> b) : beverage(b) {}
};

// 具体装饰器:牛奶
class Milk : public CondimentDecorator {
public:
    Milk(std::shared_ptr<Beverage> b) : CondimentDecorator(b) {}
    
    std::string getDescription() const override {
        return beverage->getDescription() + ", Milk";
    }
    
    double cost() const override {
        return beverage->cost() + 0.30;
    }
};

// 具体装饰器:摩卡
class Mocha : public CondimentDecorator {
public:
    Mocha(std::shared_ptr<Beverage> b) : CondimentDecorator(b) {}
    
    std::string getDescription() const override {
        return beverage->getDescription() + ", Mocha";
    }
    
    double cost() const override {
        return beverage->cost() + 0.45;
    }
};

// 客户端代码
int main() {
    // 纯浓缩咖啡
    std::shared_ptr<Beverage> beverage = std::make_shared<Espresso>();
    std::cout << beverage->getDescription() << " $" << beverage->cost() << std::endl;
    
    // 加牛奶的黑咖啡
    std::shared_ptr<Beverage> beverage2 = std::make_shared<DarkRoast>();
    beverage2 = std::make_shared<Milk>(beverage2);
    std::cout << beverage2->getDescription() << " $" << beverage2->cost() << std::endl;
    
    // 加双份摩卡的浓缩咖啡
    std::shared_ptr<Beverage> beverage3 = std::make_shared<Espresso>();
    beverage3 = std::make_shared<Mocha>(beverage3);
    beverage3 = std::make_shared<Mocha>(beverage3);
    std::cout << beverage3->getDescription() << " $" << beverage3->cost() << std::endl;
    
    return 0;
}

三、装饰模式与继承的对比

传统继承方式的局限性:

  • 功能扩展通过创建子类实现,导致类数量爆炸。
  • 功能扩展是静态的,编译时确定,无法在运行时动态调整。

装饰模式的优势:

  • 动态组合对象功能,运行时灵活扩展。
  • 避免继承导致的类层次过深问题。
  • 符合开闭原则:无需修改原有代码,即可添加新的装饰器。

四、应用场景

  1. 动态添加功能:当需要给对象动态添加功能,且不影响其他对象时,例如:
    • 图形界面组件的边框、滚动条、阴影效果。
    • 网络请求的加密、压缩、缓存功能。
  2. 替代多重继承:当使用继承会导致类爆炸时,例如:
    • 文件流的缓冲、加密、压缩处理。
    • 游戏角色的装备、技能组合。
  3. 功能增强链:当需要按顺序执行多个功能增强时,例如:
    • 日志处理(过滤、格式化、存储)。
    • HTTP 请求处理(身份验证、参数解析、权限检查)。

五、C++ 实现注意事项

  1. 接口一致性

    • 装饰器必须实现与被装饰对象相同的接口(继承同一抽象类)。
    • 确保装饰器不改变接口签名,只增强功能。
  2. 智能指针管理

    // 使用智能指针避免内存泄漏
    std::shared_ptr<Beverage> beverage = std::make_shared<Espresso>();
    beverage = std::make_shared<Mocha>(beverage);
    
  3. 初始化顺序

    • 装饰器的初始化顺序可能影响最终结果,需谨慎设计。
  4. 避免重复装饰

    • 某些场景需防止对同一对象重复应用相同装饰器。

六、装饰模式与其他设计模式的关系

  1. 适配器模式适配器模式详解

    • 适配器模式改变对象接口,装饰模式增强对象功能。
    • 适配器模式是 “适配”,装饰模式是 “增强”。
  2. 代理模式

    • 代理模式控制对象访问,装饰模式增加对象功能。
    • 代理模式的重点是访问控制,装饰模式的重点是功能扩展。
  3. 建造者模式建造者模式详解

    • 建造者模式分步构建复杂对象,装饰模式动态增强对象。
    • 建造者模式关注对象构建过程,装饰模式关注对象运行时功能。

七、实战案例:网络请求处理链

以下是一个网络请求处理链的装饰模式实现:

#include <iostream>
#include <string>
#include <memory>

// 抽象组件:请求处理器
class RequestHandler {
public:
    virtual ~RequestHandler() {}
    virtual void handleRequest(const std::string& request) const = 0;
};

// 具体组件:基础请求处理器
class BaseRequestHandler : public RequestHandler {
public:
    void handleRequest(const std::string& request) const override {
        std::cout << "Base handler processing request: " << request << std::endl;
    }
};

// 抽象装饰器:请求处理器装饰器
class RequestHandlerDecorator : public RequestHandler {
protected:
    std::shared_ptr<RequestHandler> handler;

public:
    RequestHandlerDecorator(std::shared_ptr<RequestHandler> h) : handler(h) {}
};

// 具体装饰器:日志记录
class LoggingDecorator : public RequestHandlerDecorator {
public:
    LoggingDecorator(std::shared_ptr<RequestHandler> h) : RequestHandlerDecorator(h) {}
    
    void handleRequest(const std::string& request) const override {
        std::cout << "Logging: Request received - " << request << std::endl;
        handler->handleRequest(request);
        std::cout << "Logging: Request processed" << std::endl;
    }
};

// 具体装饰器:权限检查
class AuthDecorator : public RequestHandlerDecorator {
public:
    AuthDecorator(std::shared_ptr<RequestHandler> h) : RequestHandlerDecorator(h) {}
    
    void handleRequest(const std::string& request) const override {
        std::cout << "Auth: Checking permissions..." << std::endl;
        handler->handleRequest(request);
        std::cout << "Auth: Permissions checked" << std::endl;
    }
};

// 客户端代码
int main() {
    // 创建基础处理器
    std::shared_ptr<RequestHandler> baseHandler = std::make_shared<BaseRequestHandler>();
    
    // 添加日志和权限装饰
    std::shared_ptr<RequestHandler> authHandler = std::make_shared<AuthDecorator>(baseHandler);
    std::shared_ptr<RequestHandler> loggingAuthHandler = std::make_shared<LoggingDecorator>(authHandler);
    
    // 处理请求
    loggingAuthHandler->handleRequest("GET /api/data");
    
    return 0;
}

八、优缺点分析

优点:

  • 灵活扩展:可以在运行时动态添加或删除功能。
  • 单一职责:每个装饰器专注于一个特定功能,符合单一职责原则。
  • 开闭原则:无需修改现有代码即可添加新装饰器。

缺点:

  • 复杂性增加:多层装饰会导致系统复杂,调试困难。
  • 对象嵌套:过多装饰器可能导致对象嵌套过深,影响性能。
  • 接口一致性:装饰器必须严格遵循组件接口,否则可能破坏系统。

九、C++ 标准库中的装饰模式应用

  1. 输入 / 输出流(iostream)
    • std::basic_ios是抽象组件,std::ifstreamstd::ofstream是具体组件。
    • std::ios_base::iwordstd::ios_base::pword可用于动态添加流的属性。
  2. 智能指针
    • std::shared_ptrstd::unique_ptr可视为对原始指针的装饰器,添加了内存管理功能。
  3. STL 迭代器适配器
    • std::reverse_iteratorstd::insert_iterator等是对基础迭代器的装饰。

装饰模式是 C++ 中实现对象功能动态扩展的重要工具,通过合理使用装饰器,可以构建出灵活、可维护的软件系统,同时避免继承带来的局限性。


如果这篇文章对你有所帮助,渴望获得你的一个点赞!

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到