C++设计模式——Decorator装饰器模式

一,装饰器模式简介

装饰器模式是一种结构型设计模式, 它允许在不改变现有对象的情况下,动态地将功能添加到对象中。

装饰器模式是通过创建具有新行为的对象来实现的,这些对象将原始对象进行了包装。

装饰器模式遵循开放/关闭原则,允许开发者在不修改现有代码的情况下添加新的装饰器。

日常开发中常用的装饰器属于类装饰器,通过继承父类来实现。

二,装饰器模式的结构

**1.抽象组件(Component):**被装饰的对象,声明了对外的统一接口。

**2.具体组件(ConcreteComponent):**包含抽象组件接口的具体代码实现。

**3.抽象装饰器(Decorator):**包含对抽象组件的指针或引用,并定义了与抽象组件一致的接口。

**4.具体装饰器(ConcreteDecorator):**包含抽象装饰器接口的具体代码实现,并且可以在调用对外接口之前或之后添加额外的行为。

对应UML类图:

拿生活中举例:某硬核产品的可拆卸装饰

三,装饰器模式的工作步骤

1.创建抽象组件类,定义抽象组件的对外接口,将核心功能声明在该接口中。

2.创建具体组件类,继承抽象组件类,实现抽象组件类的接口。

3.创建抽象装饰器类,继承抽象组件类,实现抽象组件类的接口,并持有一个抽象组件对象的引用。

4.创建具体装饰器类,继承抽象装饰器类,在实现核心接口之后,添加额外的接口函数。

5.在客户端中使用装饰器包装抽象组件,并调用它们的方法。

四,装饰器模式代码样例

暂时不带具体装饰器ConcreteDecorator,直接在Decorator中添加额外功能。

cpp 复制代码
#include <iostream>

class Component {
public:
    virtual void operation() = 0;
};

class ConcreteComponent : public Component {
public:
    void operation() override {
        std::cout << "From ConcreteComponent." << std::endl;
    }
};

class Decorator : public Component {
public:
    Decorator(Component& component):component_(component){}
    void operation() override {
        std::cout << "from Decorator." << std::endl;
        component_.operation();
    }

private:
    Component& component_;
};

int main() {
    ConcreteComponent concreteComponent;
    Decorator decoratedComponent(concreteComponent);
    decoratedComponent.operation();
    return 0;
}

运行结果:

bash 复制代码
from Decorator.
From ConcreteComponent.

五,装饰器模式的应用场景

**组件扩展:**在大型项目中,随着业务的增加,必定要添加新的功能,装饰器此时可以避免修改原有的基础组件。

**API增强:**当提供API给第三方进行调用时,装饰器可以用于添加额外的功能,比如日志记录、安全校验等,而调用者无需知道具体的细节。

**权限管理:**装饰器可以用来控制对原有的特定接口的访问权限。

**缓存机制:**在网络请求或数据库查询等操作中,装饰器可以用来添加额外的缓存、重试、超时处理等功能。

六,装饰器模式的优缺点

装饰器模式的优点:

1.可以动态地添加或删除对象的功能,无需修改原有的代码。

2.不影响现有对象的结构,符合开闭原则。

3.可以灵活地扩展原有对象的功能。

4.可以使用多个装饰器对象来组合多种功能。

5.使得代码可以根据需要轻松地添加或移除功能。

装饰器模式的缺点:

1.使系统中增加额外的类变量。

2.装饰器对象与原始对象之间的关系过于复杂,降低代码可读性。

七,代码实战

Demo1: 自助冰淇淋制作机

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

using namespace std;

// Component
class IceCream {
public:
    virtual string getDescription() const = 0;
    virtual double cost() const = 0;
};

// Concrete Component
class VanillaIceCream : public IceCream {
public:
    string getDescription() const override
    {
        return "Vanilla Ice Cream";
    }

    double cost() const override { return 160.0; }
};

// Decorator
class Decorator : public IceCream {
protected:
    IceCream* iceCream;

public:
    Decorator(IceCream* ic)
        : iceCream(ic)
    {
    }

    string getDescription() const override
    {
        return iceCream->getDescription();
    }

    double cost() const override
    {
        return iceCream->cost();
    }
};

// Concrete Decorator - adds chocolate topping.
class ChocolateDecorator : public Decorator {
public:
    ChocolateDecorator(IceCream* ic)
        : Decorator(ic)
    {
    }

    string getDescription() const override
    {
        return iceCream->getDescription()
            + " with Chocolate";
    }

    double cost() const override
    {
        return iceCream->cost() + 100.0;
    }
};

// Concrete Decorator - adds caramel topping.
class CaramelDecorator : public Decorator {
public:
    CaramelDecorator(IceCream* ic)
        : Decorator(ic)
    {
    }

    string getDescription() const override
    {
        return iceCream->getDescription() + " with Caramel";
    }

    double cost() const override
    {
        return iceCream->cost() + 150.0;
    }
};

int main()
{
    // Create a vanilla ice cream
    IceCream* vanillaIceCream = new VanillaIceCream();
    cout << "Order: " << vanillaIceCream->getDescription()
        << ", Cost: Rs." << vanillaIceCream->cost()
        << endl;

    // Wrap it with ChocolateDecorator
    IceCream* chocolateIceCream
        = new ChocolateDecorator(vanillaIceCream);
    cout << "Order: " << chocolateIceCream->getDescription()
        << ", Cost: Rs." << chocolateIceCream->cost()
        << endl;

    // Wrap it with CaramelDecorator
    IceCream* caramelIceCream
        = new CaramelDecorator(chocolateIceCream);
    cout << "Order: " << caramelIceCream->getDescription()
        << ", Cost: Rs." << caramelIceCream->cost()
        << endl;

    delete vanillaIceCream;
    delete chocolateIceCream;
    delete caramelIceCream;

    return 0;
}

运行结果:

cpp 复制代码
Order: Vanilla Ice Cream, Cost: Rs.160
Order: Vanilla Ice Cream with Chocolate, Cost: Rs.260
Order: Vanilla Ice Cream with Chocolate with Caramel, Cost: Rs.410

Demo2: 模拟的绘图组件

cpp 复制代码
#include <iostream>
using namespace std;

// Component
class Widget
{
public:
    virtual void draw() = 0;
};

// Concrete Component
class TextField : public Widget
{
    int width, height;
public:
    TextField(int w, int h)
    {
        width = w;
        height = h;
    }
    void draw()
    {
      cout << "TextField: " << width << "," << height;
    }
};

// Decorator
class Decorator : public Widget  
{
    Widget* wid;
public:
    Decorator(Widget* w)
    {
        wid = w;
    }
    void draw()
    {
        wid->draw();
    }
};

// Concrete Decorator
class BorderDecorator : public Decorator
{
public:
    BorderDecorator(Widget* w): Decorator(w){}
    void draw()
    {
        //基础功能
        Decorator::draw();
        //扩展功能
        cout << "\n BorderDecorator" ;
    }
};

// Concrete Decorator
class ScrollDecorator : public Decorator
{
public:
    ScrollDecorator(Widget* w): Decorator(w){}
    /*virtual*/
    void draw()
    {
        //基础功能
        Decorator::draw();
        //扩展功能
        cout << "\n ScrollDecorator";
    }
};
int main()
{
    Widget* aWidget = new BorderDecorator(
     new ScrollDecorator(new TextField(80, 24)));
    aWidget->draw();
}

运行结果:

bash 复制代码
TextField: 80,24
ScrollDecorator
BorderDecorator

八,参考阅读

https://www.pentalog.com/blog/design-patterns/decorator-design-pattern/

https://www.geeksforgeeks.org/introduction-to-decorator-pattern-in-c-design-patterns/

https://sourcemaking.com/design_patterns/decorator/cpp/2

https://sourcemaking.com/design_patterns/decorator

相关推荐
ALISHENGYA2 分钟前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(实战项目二)
数据结构·c++·算法
阿雄不会写代码3 分钟前
ubuntu安装nginx
linux·服务器·网络
蜗牛hb5 分钟前
VMware Workstation虚拟机网络模式
开发语言·学习·php
chinayu200710 分钟前
虚拟机桥接模式
linux·运维·桥接模式
1LOVESJohnny14 分钟前
Linux | scp指令基于WSL在Windows/Ubuntu系统间传输文件
linux·ubuntu·wsl·文件传输
arong_xu16 分钟前
现代C++锁介绍
c++·多线程·mutex
汤姆和杰瑞在瑞士吃糯米粑粑21 分钟前
【C++学习篇】AVL树
开发语言·c++·学习
Biomamba生信基地28 分钟前
R语言基础| 功效分析
开发语言·python·r语言·医药
DARLING Zero two♡28 分钟前
【优选算法】Pointer-Slice:双指针的算法切片(下)
java·数据结构·c++·算法·leetcode
手可摘星河30 分钟前
php中 cli和cgi的区别
开发语言·php