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

news2024/11/17 17:31:41

装饰器设计模式

  • 概念
  • 应用场景
  • 优点
  • 示例
    • 示例一
      • 代码实现
      • 运行结果
    • 示例二
      • 代码实现
      • 运行结果
    • 示例三
      • 实现代码
      • 运行结果
    • 总结

概念

装饰器设计模式,是C++设计模式中的一种。它是一种结构型设计模式,允许向现有对象动态地添加新功能,同时又不改变其结构。这种模式是通过创建一个包装对象来实现的,也就是说,实际对象被包装在装饰器类的实例中。装饰器类实现了与实际对象相同的接口,并且可以添加额外的行为。

应用场景

装饰器模式的核心是功能扩展,使用装饰器模式可以透明且动态地扩展类的功能。在不改变原有类结构的基础上,扩展新的功能。

优点

降低代码之间的耦合性,提高了灵活性,具有更好的扩展性。

示例

下面是三个简单的C++实现装饰器模式的示例,仅供理解该设计模式。

示例一

代码实现

#include <iostream>
using namespace std;

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

// 具体组件
class ConcreteComponent : public Component {
public:
    virtual void operation() {
        cout << "具体对象的操作" << endl;
    }
};

// 装饰器
class Decorator : public Component {
protected:
    Component* component;
public:
    void setComponent(Component* component) {
        this->component = component;
    }
    virtual void operation() {
        if (component != nullptr) {
            component->operation();
        }
    }
};

// 具体装饰器
class ConcreteDecoratorA : public Decorator {
public:
    virtual void operation() {
        Decorator::operation(); // 调用父类的operation
        addedBehavior();
    }
    void addedBehavior() {
        cout << "为具体构件A扩展的操作" << endl;
    }
};

class ConcreteDecoratorB : public Decorator {
public:
    virtual void operation() {
        Decorator::operation(); // 调用父类的operation
        addedBehavior();
    }
    void addedBehavior() {
        cout << "为具体构件B扩展的操作" << endl;
    }
};

int main() {
    Component* component = new ConcreteComponent();
    Decorator* decorator1 = new ConcreteDecoratorA();
    Decorator* decorator2 = new ConcreteDecoratorB();

    decorator1->setComponent(component);
    decorator2->setComponent(decorator1);
    decorator2->operation();

    delete decorator2;
    delete decorator1;
    delete component;

    return 0;
}

在这个示例中,Component 是接口,定义了操作的抽象方法。ConcreteComponent 是具体的对象。Decorator 是装饰器类,继承自 Component,并包含一个指向 Component 对象的指针。ConcreteDecoratorA 和 ConcreteDecoratorB 是具体的装饰器类,继承自 Decorator,并在 operation 方法中扩展了额外的行为。

在 main 函数中,我们创建了一个具体的对象 component,然后通过 ConcreteDecoratorA 和 ConcreteDecoratorB 对其进行装饰,最终调用 decorator2 的 operation 方法。

运行结果

在这里插入图片描述

示例二

使用装饰器模式实现一个计算图形面积的程序,并添加日志记录功能。

代码实现

#include <iostream>  
#include <string>  
  
// 定义一个接口类  
class Shape {  
public:  
    virtual double getArea() = 0;  
};  
  
// 实现接口类的具体类  
class Rectangle : public Shape {  
private:  
    double width;  
    double height;  
public:  
    Rectangle(double w, double h) : width(w), height(h) {}  
    double getArea() override {  
        std::cout << "Rectangle::getArea() - calculating area..." << std::endl;  
        return width * height;  
    }  
};  
  
// 实现一个装饰器类,用于给具体类添加额外的功能  
class ShapeDecorator : public Shape {  
protected:  
    Shape* decoratedShape; // 保存一个指向被装饰对象的指针  
public:  
    ShapeDecorator(Shape* shape) : decoratedShape(shape) {}  
    double getArea() override {  
        return decoratedShape->getArea(); // 调用被装饰对象的操作  
    }  
};  
  
// 具体的装饰器类,添加日志记录功能  
class LoggingShapeDecorator : public ShapeDecorator {  
private:  
    std::string message;  
public:  
    LoggingShapeDecorator(Shape* shape, std::string msg) : ShapeDecorator(shape), message(msg) {}  
    double getArea() override {  
        std::cout << message << " - starting calculation..." << std::endl;  
        double result = decoratedShape->getArea(); // 调用被装饰对象的操作  
        std::cout << message << " - calculation complete." << std::endl;  
        return result;  
    }  
};  
  
int main() {  
    Shape* rectangle = new Rectangle(5, 10); // 创建一个具体对象  
    Shape* loggingRectangle = new LoggingShapeDecorator(rectangle, "Rectangle::getArea()"); // 创建一个被装饰的对象,并添加日志记录功能  
    std::cout << "Area: " << rectangle->getArea() << std::endl; // 输出 "Rectangle::getArea() - calculating area..." 和 "Area: 50"  
    std::cout << "Area (with logging): " << loggingRectangle->getArea() << std::endl; // 输出 "Rectangle::getArea() - starting calculation...", "Rectangle::getArea() - calculating area...", "Rectangle::getArea() - calculation complete." 和 "Area (with logging): 50"  
    delete rectangle; // 释放内存  
    delete loggingRectangle; // 释放内存  
    return 0;  
}

运行结果

在这里插入图片描述

示例三

使用装饰器模式编写一个绘图功能,并模拟添加一些额外的功能。

实现代码

#include <iostream>  
#include <string>  
  
// 定义一个接口类  
class Shape {  
public:  
    virtual void draw() = 0;  
};  
  
// 实现接口类的具体类  
class Rectangle : public Shape {  
public:  
    void draw() override {  
        std::cout << "Rectangle::draw()" << std::endl;  
    }  
};  
  
// 实现一个装饰器类,用于给具体类添加额外的功能  
class ShapeDecorator : public Shape {  
protected:  
    Shape* decoratedShape; // 保存一个指向被装饰对象的指针  
public:  
    ShapeDecorator(Shape* shape) : decoratedShape(shape) {}  
    void draw() override {  
        decoratedShape->draw(); // 调用被装饰对象的操作  
    }  
};  
  
// 具体的装饰器类,添加新的功能  
class RedShapeDecorator : public ShapeDecorator {  
public:  
    RedShapeDecorator(Shape* shape) : ShapeDecorator(shape) {}  
    void draw() override {  
        decoratedShape->draw(); // 调用被装饰对象的操作  
        std::cout << "RedShapeDecorator::draw() - draw red border" << std::endl;  
    }  
};  
  
int main() {  
    Shape* rectangle = new Rectangle(); // 创建一个具体对象  
    Shape* redRectangle = new RedShapeDecorator(new Rectangle()); // 创建一个被装饰的对象  
    rectangle->draw(); // 输出 "Rectangle::draw()"  
    redRectangle->draw(); // 输出 "Rectangle::draw()" 和 "RedShapeDecorator::draw() - draw red border"  
    delete rectangle; // 释放内存  
    delete redRectangle; // 释放内存  
    return 0;  
}

运行结果

在这里插入图片描述

总结

装饰器设计模式其本质上还是使用多态的原理,提供了一种可扩展功能的设计模式。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用Python将OSS文件免费下载到本地:第一步 列举OSS文件

大家好&#xff0c;我是水滴~~ 本文将介绍了使用的知识点、以及列举OSS文件的代码、并对该代码进行详细解析、最后给出部署方案&#xff0c;希望能对你有所帮助&#xff01; 《Python入门核心技术》专栏总目录・点这里 文章目录 1. 本文知识点1.1 datetime 模块1.2 OSS Python…

PyQt5连接mysql失败解决

一&#xff1a;背景 最近研究一个项目&#xff0c;里面用的Pyqt5编写的桌面应用&#xff0c;跑了下源码发现连接数据库那块出来问题&#xff0c;最终调试发现里面用的QtSql去连接mysql提示驱动找不到。 具体报错信息如下&#xff1a; Could not parse stylesheet of object …

使用VBA字典,进行数据分类汇总

使用VBA字典&#xff0c;进行数据分类汇总 VBA的字典共有两列&#xff0c;第一列是key&#xff0c;不允许有重复的元素&#xff1b;第二列是item&#xff0c;也就是key对应的值&#xff0c;item的值是可以有重复的值的。 字典的主要操作有读和写。 写操作 d(key)item&#…

直流电、交流电和发电机、接地、变压器

直流电 此节内容主要摘录自&#xff1a;图文详解直流电与直流电路基本知识 直流电是指电流方向不随时间作周期性变化&#xff0c;由正极流向负极&#xff0c;但电流的大小可能会变化的电流。直流电可以分为稳定&#xff08;恒定&#xff09;直流和脉动直流两种&#xff0c;如下…

迪文屏开发保姆级教程—背景图ICL文件生成

本篇文章主要介绍了在DGBUS平台上生成页面背景图片库&#xff0c;32xx.ICL文件的方法。 文章目录 一、前言 开发环境 二、具体步骤 1.打开软件 2.选定参数 3.导入背景图片 4.然后点击生成&#xff0c;​编辑 三、容易踩得坑 一、前言 本篇文章主要介绍了在DGBUS平台上生…

SQLturning:定位连续值范围起点和终点

在上一篇blog说到&#xff0c;如何去优化查询连续值范围&#xff0c;没看过的朋友&#xff0c;上篇blog链接[在此]。(https://blog.csdn.net/weixin_42575078/article/details/135067645?spm1001.2014.3001.5501) 那么今天来说说怎么将连续的数据合并&#xff0c;然后返回合并…

红米k40刷机澎湃OS

红米k40线刷澎湃OS&#xff0c;MIUI→HyperOS 1.0.23.12.9 博主自己也是个小白 rom包免费获取与体验请关注公众号&#xff1a;YouLinw的ROM日常 资料备份 使用小米自带的打包备份工具&#xff0c;将文件备份到电脑上 或使用小米自带的云服务功能&#xff0c;我开了会员。换了…

【数学建模】《实战数学建模:例题与讲解》第十三讲-相关分析(含Matlab代码)

【数学建模】《实战数学建模&#xff1a;例题与讲解》第十三讲-相关分析&#xff08;含Matlab代码&#xff09; 基本概念典型相关分析综合评价模型对应分析因子分析聚类分析 习题10.41. 题目要求2.解题过程3.程序 习题10.51. 题目要求2.解题过程3.程序 习题10.6&#xff08;1&a…

C : DS二叉排序树之删除(详细思路解答)

Description 给出一个数据序列&#xff0c;建立二叉排序树&#xff0c;并实现删除功能 对二叉排序树进行中序遍历&#xff0c;可以得到有序的数据序列 Input 第一行输入t&#xff0c;表示有t个数据序列 第二行输入n&#xff0c;表示首个序列包含n个数据 第三行输入n个数据…

《PySpark大数据分析实战》-15.云服务模式Databricks介绍创建集群

&#x1f4cb; 博主简介 &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是wux_labs。&#x1f61c; 热衷于各种主流技术&#xff0c;热爱数据科学、机器学习、云计算、人工智能。 通过了TiDB数据库专员&#xff08;PCTA&#xff09;、TiDB数据库专家&#xff08;PCTP…

FastAPI访问/docs接口文档显示空白、js/css无法加载

如图&#xff1a; 原因是FastAPI的接口文档默认使用https://cdn.jsdelivr.net/npm/swagger-ui-dist5.9.0/swagger-ui.css 和https://cdn.jsdelivr.net/npm/swagger-ui-dist5.9.0/swagger-ui-bundle.js 来渲染页面&#xff0c;而这两个URL是外网的CDN&#xff0c;在国内响应超…

云仓酒庄的品牌雷盛红酒LEESON分享红酒存放几年质量最佳?

云仓酒庄的品牌雷盛红酒LEESON分享对于酒的看法&#xff0c;有人认为“酒是陈的香”&#xff0c;酒越老越好。不过对于葡萄酒来说&#xff0c;这种说法不完全对&#xff0c;如果一款葡萄酒等待的时间太久&#xff0c;未必是件好事。对待葡萄酒也要把握一个“度”&#xff0c;既…

STM32启动过程

STM32启动模式&#xff08;自举模式&#xff09; M3/3/7等内核&#xff0c;复位后做的第一件事&#xff1a; 从地址0x0000 0000处取出栈指针MSP的初始值&#xff0c;该值就是栈顶地址。从地址0x0000 0004处取出程序计数器指针PC的初始值&#xff0c;该值是复位向量。 芯片厂商…

【BIG_FG_CSDN】*VMware17pro*Linux*Redhit6网络管理(个人向——学习笔记)

物理机中的网络 查看物理网络的方法 “网络连接”—>单点选中网络的选项-->菜单栏中“查看此连接状态”-->“详细信息” “网络连接”中的VM网卡 在主机上对应的有VMware Network Adapter VMnet1和VMware Network Adapter VMnet8两块虚拟网卡&#xff0c;它们分别…

Python四种配色方案,适合科研的配色

1、Plasma&#xff08;等高线图颜色&#xff09;2、Inferno&#xff08;黑热图颜色&#xff09;3、Cividis&#xff08;较好的配色方案&#xff0c;适用于色盲&#xff09;4、Viridis&#xff08;绿色主导的配色方案&#xff09; 下面这四种配色是不需要指定的&#xff0c;Pyth…

个微和企微,哪个做私域流量的优势更大?

个人微信和企业微信是目前最为常用的私域经营平台&#xff0c;那在功能和使用上都有哪些区别&#xff1a; 1、开通对象不同&#xff1a; 个人微信是个人用户&#xff0c;个人就可以申请开通使用&#xff1b; 企业微信则要由企业在官方网站申请开通&#xff0c;并完成实名认证…

泰坦陨落2找不到msvcr120文件的修复方法,分享多种解决方法

在玩泰坦陨落2这款游戏时&#xff0c;有些玩家可能会遇到找不到msvcr120.dll文件的问题。这个问题可能是由于游戏缺少必要的运行库导致的。下面我将分享一些解决这个问题的方法&#xff0c;希望对大家有所帮助。 一、问题分析 msvcr120.dll是Microsoft Visual C Redistributab…

C语言进阶第十一节 --------程序环境和预处理(包含宏的解释)

作者前言 &#x1f382; ✨✨✨✨✨✨&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; ​&#x1f382; 作者介绍&#xff1a; &#x1f382;&#x1f382; &#x1f382; &#x1f389;&#x1f389;&#x1f389…

一招教你如何绕过OpenAI API key创建时需要手机号验证

一招教你如何绕过OpenAI API key创建时需要手机号验证 虽然现在 ChatGPT 注册门槛极大地降低。但是&#xff0c;如果你是开发者或者需要第三方应用接入ChatGPT&#xff0c;此时就需要获取一个 API key&#xff0c;然而你可能会发现在你在创建 key 的过程中需要进行手机号验证。…

可控硅(晶闸管)原理图及可控硅工作原理分析

可控硅(晶闸管)原理图 可控硅T在工作过程中&#xff0c;它的阳极A和阴极K与电源和负载连接&#xff0c;组成可控硅的主电路&#xff0c;可控硅的门极G和阴极K与控制可控硅的装置连接&#xff0c;组成可控硅的控制电路。 从可控硅的内部分析工作过程&#xff1a; 可控硅是四层…