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

一,装饰器模式简介

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

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

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

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

二,装饰器模式的结构

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

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

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

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

对应UML类图:

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

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

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

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

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

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

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

四,装饰器模式代码样例

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

#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;
}

运行结果:

from Decorator.
From ConcreteComponent.

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

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

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

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

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

六,装饰器模式的优缺点

装饰器模式的优点:

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

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

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

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

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

装饰器模式的缺点:

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

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

七,代码实战

Demo1: 自助冰淇淋制作机

#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;
}

运行结果:

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: 模拟的绘图组件

#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();
}

运行结果:

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/710032.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AI办公自动化:批量在多个Word文档中插入对应图片

工作任务&#xff1a;文件夹中有多个word文档和word文档名称一致的图片&#xff0c;要把这些图片都插入到word文档中 在chatpgt中输入提示词&#xff1a; 你是一个Python编程专家&#xff0c;写一个Python脚本&#xff0c;具体步骤如下&#xff1a; 打开文件夹&#xff1a;F:…

c++/c输出double问题

这个我大抵能理解&#xff0c;%d是int嘛。 这是为啥&#xff1f; 这样又好了&#xff1f; 这我也能理解 这也可以 这也对&#xff1f; &#xff08;我知道我呢个函数为什么不对了&#xff0c;我的函数写的是int(&#xff09;) 附&#xff1a;保留几位小数&#xff1a; %.2f

手把手教你入门vue+springboot开发(三)--登录功能后端

文章目录 前言一、redis安装二、后端代码1.修改application.yml文件2.增加utils文件3.增加Result类4.修改UserController类5.修改UserMapper类6.修改UserService和UserServiceImpl类7.增加LoginInterceptor类8.增加WebConfig类9.修改pom.xml文件 前言 前两篇我们用vuespringbo…

基于负相关误差函数的4集成BP神经网络matlab建模与仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) 2.算法运行软件版本 MATLAB2022a 3.部分核心程序 ...............................................................…

XILINX 7系列XDMA使用_IP核介绍以及工程搭建

文章目录 一、XDMA IP核1.1、接口说明1.2、配置页说明 二、XDMA工程搭建2.1、BD搭建2.2 Linux下XDMA驱动安装2.3 Linux下使用XDMA进行数据传输 一、XDMA IP核 1.1、接口说明 sys_clk&#xff1a;主机给PCIE提供的时钟信号&#xff0c;通过原理图查看 sys_rst_n&#xff1a;主机…

宠物健康顾问系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;顾问管理&#xff0c;用户管理&#xff0c;健康知识管理&#xff0c;管理员管理&#xff0c;论坛管理&#xff0c;公告管理 顾问账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;顾…

宝藏速成秘籍(3)选择排序法

一、前言 1.1、概念 选择排序法&#xff08;Selection Sort&#xff09;是一种简单直观的排序算法。它的基本思想是&#xff1a;每次从待排序的数组中选择最小&#xff08;或最大&#xff09;的元素&#xff0c;将其放在已排序部分的末尾&#xff0c;直到所有元素都排序完毕。…

资源分享—2021版乡级制图规范符号库

汇总整理超图平台软件相关的各类资源&#xff08;包括但不限于符号库、地图模板、地理处理模型等&#xff09;&#xff0c;助力项目的高效制图、提高数据生产效率等业务。 本次分享新版国土空间规划【2021版乡级制图规范符号库】&#xff0c;提供SuperMap格式符号库下载。 符…

简单了解CPU的工作原理

目录 一、基本结构以及对应功能 &#xff08;1&#xff09;基本结构 &#xff08;2&#xff09;几个重要寄存器的详细介绍 操作码 (Opcode) 操作数 (Operands) 指令表 (Instruction Table) 第一个&#xff1a;程序计数器 (PC) 第二个&#xff1a;指令寄存器 (IR&#x…

头歌资源库(3)爬楼梯问题

一、 问题描述 二、算法思想 假设要爬上n阶楼梯&#xff0c;我们可以将问题分解为子问题&#xff1a;爬到第n-1阶楼梯的方法数加上爬到第n-2阶楼梯的方法数加上爬到第n-3阶楼梯的方法数。 设f(n)表示爬到第n阶楼梯的方法数&#xff0c;则有递推关系&#xff1a;f(n) f(n-1…

有声读物管理平台Booksonic-Air

老苏最近在听评书&#xff0c;所以想找个软件来管理和收听&#xff0c;找了一圈&#xff0c;感觉 Booksonic-Air 可能能满足老苏的需求。 什么是 Booksonic-Air &#xff1f; Booksonic-Air 是一个用于流式传输有声读物的服务器&#xff0c;是原始 Booksonic 服务器的后继者。…

windows上运行arm32架构的安卓模拟器

说明 主要功能&#xff1a;在win10上研究和学习32位arm汇编指令的执行 环境如下 主机环境: windows10 目标模拟器环境:armeabi-v7a调试环境搭建 1、下载android studio [下载地址](https://developer.android.com/studio?hlzh-cn) ![在这里插入图片描述](https://img-blog…

RedHat9 | Mariadb数据库的配置与管理

一、实验环境 1、Mariadb数据库介绍 MariaDB数据库管理系统是一个开源的关系型数据库管理系统&#xff0c;与MySQL高度兼容&#xff0c;并提供了更多的功能和性能优化。 起源和背景 MariaDB是MySQL的一个分支&#xff0c;主要由开源社区维护。由MySQL的创始人Michael Widen…

【面试干货】Java集合类详解:List、Set、Queue、Map、Stack的特点与用法

【面试干货】Java集合类详解&#xff1a;List、Set、Queue、Map、Stack的特点与用法 1、Map1.1 特点1.2 用法1.3 常见的实现类 2、Set2.1 特点2.2 用法2.3 常见的实现类 3、List3.1 特点3.2 用法3.3 常见的实现类 4、Queue4.1 特点4.2 用法4.3 常见的实现类 5、Stack5.1 特点5.…

Springboot实现微信小程序登录功能

目录 一 什么是微信登录功能 二 实现微信登录功能的整体逻辑 三 微信登录功能实现步骤 一 什么是微信登录功能 微信小程序登录功能一般用于开发微信小程序的时候&#xff0c;我们需要使用微信授权登录我们的微信小程序&#xff0c;本篇博客就微信小程序实现微信授权登录以及s…

基于LangChain-Chatchat实现的RAG-本地知识库的问答应用[2]-简洁部署版

基于LangChain-Chatchat实现的RAG-本地知识库的问答应用[2]-简洁部署版 1.环境要求 1.1 软件要求 要顺利运行本代码,请按照以下系统要求进行配置 已经测试过的系统 Linux Ubuntu 22.04.5 kernel version 6.7其他系统可能出现系统兼容性问题。 最低要求 该要求仅针对标准模…

OpenStack入门体验及一键部署

OpenStack入门体验 技能目标&#xff1a; 了解云计算概念 了解OpenStack 了解OpenStack的构成 会OpenStack单机环境一键部署 从控制台认识OpenStack各项功能会 通过OpenStack控制台创建云主机 什么是云计算 云计算(cloudcomputing)是一种基于网络的超级计算模式&a…

Docker安装Nginx(各种错误版)

Docker安装-CSDN博客 安装启动Docker之后 docker run -d -p 81:81 --name nginx nginx 这样没有指定版本 docker run&#xff1a;启动一个新的容器。-d&#xff1a;以分离模式运行容器&#xff08;后台运行&#xff09;。-p 81:81&#xff1a;将主机的 81 端口映射到容器的 …

用Vue3和p5.js打造一个交互式数据可视化仪表盘

本文由ScriptEcho平台提供技术支持 项目地址&#xff1a;传送门 基于 Vue.js 集成 p5.js 实现交互式波形图 应用场景介绍 在数据可视化领域&#xff0c;波形图广泛应用于展示动态变化的数据&#xff0c;如声音信号、心跳曲线等。通过动态绘制波形图&#xff0c;用户可以直观…

网络标准架构--OSI七层、四层

OSI七层网络架构&#xff0c;以及实际使用的四层网络架构。