07结构型设计模式——装饰器模式

一、装饰器模式简介

装饰器模式( Decorator Pattern)又称包装模式。通过一种面向客户端透明的方式来扩展对象的功能,是继承关系的一个替换方案。装饰器模式就是把要添加的附加功能分别放在单独的类中,并让这个类包含它要装饰的对象,当需要执行时,客户端可以有选择地、按顺序地使用装饰功能包装对象。

GoF一书对装饰器模式的介绍

二、装饰器模式的用处

装饰器模式允许在不改变对象结构的情况下,动态地给一个对象添加功能。这种模式通过创建一个装饰类来包装原有类的对象,从而增加新的功能。装饰器模式是面向对象编程中常用的一种设计模式,适用于需要在运行时动态地扩展对象功能的情况。

  1. 动态扩展功能

    • 装饰器模式允许在不修改原有类的情况下,通过添加装饰器类来动态地扩展对象的功能。这在需要根据不同的需求或条件来增加功能时非常有用。
  2. 增强类的灵活性

    • 通过组合装饰器对象,可以灵活地组合和扩展功能。这种组合的方式比子类化更为灵活,因为它允许在运行时决定具体的功能组合,而不需要修改现有类的代码。
  3. 避免类爆炸

    • 如果每种功能的组合都需要一个新的子类,那么子类数量将会大幅增加,导致类的管理变得困难。装饰器模式可以通过在运行时组合不同的装饰器对象来解决这个问题,从而避免了创建大量的子类。
  4. 遵循开闭原则

    • 装饰器模式遵循了开闭原则,即"对扩展开放,对修改关闭"。通过使用装饰器来增加功能,你可以在不修改原有类的情况下增加新的功能。
  5. 灵活的功能组合

    • 可以在运行时灵活地组合不同的装饰器,这使得功能组合非常灵活。你可以选择不同的装饰器来满足具体的需求,而不需要重新设计整个类层次结构。

三、装饰器模式的设计方法

基础类和装饰器:

  1. 定义基础类Cup:它代表一个基础的水杯。

  2. 定义装饰器基类CupDecorator:继承自Cup,用于装饰基本水杯。

  3. 定义具体装饰器:每个装饰器代表一种调料。

decorator.cpp

cpp 复制代码
#include <iostream>
#include <string>
#include <vector>

// 水杯
class Cup {
public:
    virtual ~Cup() = default;
    virtual std::string getDescription() const {
        return "水杯放入";
    }
    virtual double cost() const {
        return 0.0; // 水杯的成本
    }
};

// 装饰器
class CupDecorator : public Cup {
public:
    CupDecorator(Cup* cup) : cup(cup) {}
    virtual ~CupDecorator() {
        delete cup;
    }
    std::string getDescription() const override {
        return cup->getDescription();
    }
    double cost() const override {
        return cup->cost();
    }

protected:
    Cup* cup;
};

// 调料
class CoffeePowderDecorator : public CupDecorator {
public:
    CoffeePowderDecorator(Cup* cup) : CupDecorator(cup) {}

    std::string getDescription() const override {
        return cup->getDescription() + ", Coffee Powder";
    }

    double cost() const override {
        return cup->cost() + 2.0; // 咖啡粉的附加费用
    }
};

class BrownSugarDecorator : public CupDecorator {
public:
    BrownSugarDecorator(Cup* cup) : CupDecorator(cup) {}

    std::string getDescription() const override {
        return cup->getDescription() + ", Brown Sugar";
    }

    double cost() const override {
        return cup->cost() + 1.0; // 红糖的附加费用
    }
};

class LemonSliceDecorator : public CupDecorator {
public:
    LemonSliceDecorator(Cup* cup) : CupDecorator(cup) {}

    std::string getDescription() const override {
        return cup->getDescription() + ", Lemon Slice";
    }

    double cost() const override {
        return cup->cost() + 0.5; // 柠檬片的附加费用
    }
};

class GojiBerriesDecorator : public CupDecorator {
public:
    GojiBerriesDecorator(Cup* cup) : CupDecorator(cup) {}

    std::string getDescription() const override {
        return cup->getDescription() + ", Goji Berries";
    }

    double cost() const override {
        return cup->cost() + 1.5; // 枸杞的附加费用
    }
};

class RedDateSlicesDecorator : public CupDecorator {
public:
    RedDateSlicesDecorator(Cup* cup) : CupDecorator(cup) {}

    std::string getDescription() const override {
        return cup->getDescription() + ", Red Date Slices";
    }

    double cost() const override {
        return cup->cost() + 2.0; // 红枣圈的附加费用
    }
};

class ChrysanthemumDecorator : public CupDecorator {
public:
    ChrysanthemumDecorator(Cup* cup) : CupDecorator(cup) {}

    std::string getDescription() const override {
        return cup->getDescription() + ", Chrysanthemum";
    }

    double cost() const override {
        return cup->cost() + 1.0; // 菊花的附加费用
    }
};

class YellowTeaDecorator : public CupDecorator {
public:
    YellowTeaDecorator(Cup* cup) : CupDecorator(cup) {}

    std::string getDescription() const override {
        return cup->getDescription() + ", Yellow Tea";
    }

    double cost() const override {
        return cup->cost() + 2.5; // 黄芽的附加费用
    }
};

class MilkDecorator : public CupDecorator {
public:
    MilkDecorator(Cup* cup) : CupDecorator(cup) {}

    std::string getDescription() const override {
        return cup->getDescription() + ", Milk";
    }

    double cost() const override {
        return cup->cost() + 2.5; // 牛奶的附加费用
    }
};

class WaterDecorator : public CupDecorator {
public:
    WaterDecorator(Cup* cup) : CupDecorator(cup) {}

    std::string getDescription() const override {
        return cup->getDescription() + ", Water";
    }

    double cost() const override {
        return cup->cost() + 0.0; // 水免费
    }
};

void printService(Cup* cup) {
    std::cout << "Description: " << cup->getDescription() << std::endl;
    std::cout << "Cost: $" << cup->cost() << std::endl;
}

// 纯水套餐
void servicePureWater() {
    Cup* myCup = new Cup();
    myCup = new WaterDecorator(myCup);
    printService(myCup);
    delete myCup;
}

// 咖啡套餐
void serviceCoffee() {
    Cup* myCup = new Cup();
    myCup = new WaterDecorator(myCup);
    myCup = new CoffeePowderDecorator(myCup);
    myCup = new BrownSugarDecorator(myCup);
    myCup = new MilkDecorator(myCup);
    printService(myCup);
    delete myCup;
}

// 饮料套餐
void serviceDrink() {
    Cup* myCup = new Cup();
    myCup = new WaterDecorator(myCup);
    myCup = new LemonSliceDecorator(myCup);
    myCup = new ChrysanthemumDecorator(myCup);
    printService(myCup);
    delete myCup;
}

// 养生套餐
void serviceHealth() {
    Cup* myCup = new Cup();
    myCup = new WaterDecorator(myCup);
    myCup = new YellowTeaDecorator(myCup);
    myCup = new GojiBerriesDecorator(myCup);
    myCup = new RedDateSlicesDecorator(myCup);
    printService(myCup);
    delete myCup;
}

int main() {
    servicePureWater();
    serviceCoffee();
    serviceDrink();
    serviceHealth();
    return 0;
}

运行效果

四、总结

通过装饰器模式(Decorator Pattern)可以灵活地组合各种调料,而不需要修改基础Cup类的代码去继承或者依赖什么的,只需要添加装饰器和要装饰的功能即可。装饰器模式的优点在于它提供了一种非常灵活的方式来扩展对象的功能。即通过装饰器动态的给一个对象添加一些额外的职责。就增加功能来说,此模式比生成子类更为灵活。

相关推荐
爱吃生蚝的于勒16 分钟前
一文学会c++继承 组合
java·c语言·开发语言·数据结构·c++·算法·蓝桥杯
愿天堂没有C++34 分钟前
剑指offer第2版——面试题1:赋值运算符函数
c++·面试
程序猿编码4 小时前
二进制签名查找器(Aho-Corasick 自动机):设计思路与实现原理(C/C++代码实现)
c语言·c++·网络安全·二进制·逆向工程·ac自动机
R-G-B4 小时前
【35】C++实战篇—— string字符串与int、float数据合并成一个新的字符串
c++·string字符串与int·string字符串与float·string与int合并字符串·string与float合成串
weixin_307779137 小时前
Redis Windows迁移方案与测试
c++·windows·redis·算法·系统架构
zm9 小时前
bool 类型转换运算符重载
c++
小指纹9 小时前
cf--思维训练
c++·算法·macos·ios·objective-c·cocoa
小指纹9 小时前
河南萌新联赛2025第(四)场【补题】
数据结构·c++·算法·macos·objective-c·cocoa·图论
菜鸟555559 小时前
河南萌新联赛2025第四场-河南大学
c++·算法·思维·河南萌新联赛
源远流长jerry9 小时前
C++、STL面试题总结(二)
jvm·c++