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

相关推荐
lqqjuly3 小时前
特殊的“Undefined Reference xxx“编译错误
c语言·c++
冰红茶兑滴水4 小时前
云备份项目--工具类编写
linux·c++
刘好念4 小时前
[OpenGL]使用 Compute Shader 实现矩阵点乘
c++·计算机图形学·opengl·glsl
酒鬼猿4 小时前
C++进阶(二)--面向对象--继承
java·开发语言·c++
姚先生975 小时前
LeetCode 209. 长度最小的子数组 (C++实现)
c++·算法·leetcode
小王爱吃月亮糖5 小时前
QT开发【常用控件1】-Layouts & Spacers
开发语言·前端·c++·qt·visual studio
aworkholic6 小时前
opencv sdk for java中提示无stiching模块接口的问题
java·c++·opencv·jni·opencv4android·stiching
程序员老冯头6 小时前
第十六章 C++ 字符串
开发语言·c++
Xenia2236 小时前
复习篇~第二章程序设计基础
c++·算法
想睡觉 . 我也想睡觉 .6 小时前
【C++算法】1.【模板】前缀和
开发语言·c++·算法