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类的代码去继承或者依赖什么的,只需要添加装饰器和要装饰的功能即可。装饰器模式的优点在于它提供了一种非常灵活的方式来扩展对象的功能。即通过装饰器动态的给一个对象添加一些额外的职责。就增加功能来说,此模式比生成子类更为灵活。

相关推荐
奋斗的小花生1 小时前
c++ 多态性
开发语言·c++
闲晨1 小时前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
UestcXiye3 小时前
《TCP/IP网络编程》学习笔记 | Chapter 3:地址族与数据序列
c++·计算机网络·ip·tcp
霁月风4 小时前
设计模式——适配器模式
c++·适配器模式
jrrz08284 小时前
LeetCode 热题100(七)【链表】(1)
数据结构·c++·算法·leetcode·链表
咖啡里的茶i4 小时前
Vehicle友元Date多态Sedan和Truck
c++
WaaTong5 小时前
《重学Java设计模式》之 单例模式
java·单例模式·设计模式
海绵波波1075 小时前
Webserver(4.9)本地套接字的通信
c++
@小博的博客5 小时前
C++初阶学习第十弹——深入讲解vector的迭代器失效
数据结构·c++·学习
爱吃喵的鲤鱼6 小时前
linux进程的状态之环境变量
linux·运维·服务器·开发语言·c++