【GeekBand】C++设计模式笔记6_Decorator_装饰模式

news2024/10/7 1:03:46

1. “单一职责”模式

  • 在软件组件的设计中,如果责任划分的不清晰,使用继承得到的结果往往是随着需求的变化,子类急剧膨胀,同时充斥着重复代码,这时候的关键是划清责任
  • 典型模式
    • Decorator
    • Bridge

2. Decorator 装饰模式

2.1 动机(Motivation)

  • 在某些情况下我们可能会 “过度地使用继承来扩展对象的功能”,由于继承为类型引入的静态特质,使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多子类的膨胀。
  • 如何使 “对象功能的扩展” 能够根据需要来动态地实现?同时避免 “扩展功能的增多” 带来的子类膨胀问题?从而使得任何 “功能扩展变化” 所导致的影响降为最低?

2.2 模式定义

动态(组合)地给一个对象增加一些额外的职责。就增加功能而言,Decorator 模式比生成子类(继承)更为灵活(消除重复代码&减少子类个数)。
——《设计模式》GoF

2.3 实例代码

2.3.1 decorator1
// 流基类
class Stream {
public:
	// 纯虚函数
    virtual char Read(int number) = 0;
    virtual void Seek(int position) = 0;
    virtual void Write(char data) = 0;
    
    // 析构函数
    virtual ~Stream() {}
    
};

/******************** 主体类 ********************/
// 文件流类
class FileStream : public Stream {
public:
    virtual char Read(int number) {
        // 读文件流
    }
    
    virtual void Seek(int position) {
        // 定位文件流
    }
    
    virtual void Write(char data) {
        // 写文件流
    }
    
};

// 网络流类
class NetworkStream : public Stream {
public:
    virtual char Read(int number) {
        // 读网络流
    }
    
    virtual void Seek(int position) {
        // 定位网络流
    }
    
    virtual void Write(char data) {
        // 写网络流
    }
    
};

// 内存流类
class MemoryStream : public Stream {
public:
    virtual char Read(int number) {
        // 读内存流
    }
    
    virtual void Seek(int position) {
        // 定位内存流
    }
    
    virtual void Write(char data) {
        // 写内存流
    }
    
};

/******************** 扩展操作 ********************/
// 加密文件流类,继承文件流类
class CryptoFileStream : public FileStream {
public:
    virtual char Read(int number) { 
        // 额外的加密操作...
        FileStream::Read(number);	// 读文件流,调用父类函数
    }
    
    virtual void Seek(int position) {
        // 额外的加密操作...
        FileStream::Seek(position);	// 定位文件流,调用父类函数
        // 额外的加密操作...
    }
    
    virtual void Write(byte data) {
        // 额外的加密操作...
        FileStream::Write(data);	// 写文件流,调用父类函数
        // 额外的加密操作...
    }
};

// 加密网络流类,继承网络流类
class CryptoNetworkStream : public NetworkStream {
public:
    virtual char Read(int number) {  
        // 额外的加密操作...
        NetworkStream::Read(number);	// 读网络流,调用父类函数
    }
    
    virtual void Seek(int position) {
        // 额外的加密操作...
        NetworkStream::Seek(position);	// 定位网络流,调用父类函数
        // 额外的加密操作...
    }
    
    virtual void Write(byte data) {
        // 额外的加密操作...
        NetworkStream::Write(data);		// 写网络流,调用父类函数
        // 额外的加密操作...
    }
};

// 加密内存流类,继承内存流类
class CryptoMemoryStream : public MemoryStream {
public:
    virtual char Read(int number) {
        // 额外的加密操作...
        MemoryStream::Read(number);		// 读内存流,调用父类函数
    }
    
    virtual void Seek(int position) {
        // 额外的加密操作...
        MemoryStream::Seek(position);	// 定位内存流,调用父类函数
        // 额外的加密操作...
    }
    
    virtual void Write(byte data) {
        // 额外的加密操作...
        MemoryStream::Write(data);		// 写内存流,调用父类函数
        // 额外的加密操作...
    }
};

// 缓存文件流类
class BufferedFileStream : public FileStream {
    // ...
};

// 缓存网络流类
class BufferedNetworkStream : public NetworkStream {
    // ...
};

// 缓存内存流类
class BufferedMemoryStream : public MemoryStream {
    // ...
}

// 加密缓存文件流类,继承文件流
class CryptoBufferedFileStream : public FileStream {
public:
    virtual char Read(int number) {
        // 额外的加密操作...
        // 额外的缓冲操作...
        FileStream::Read(number);	// 读文件流
    }
    
    virtual void Seek(int position) {
        // 额外的加密操作...
        // 额外的缓冲操作...
        FileStream::Seek(position);	// 定位文件流
        // 额外的加密操作...
        // 额外的缓冲操作...
    }
    
    virtual void Write(byte data) {
        // 额外的加密操作...
        // 额外的缓冲操作...
        FileStream::Write(data);	// 写文件流
        // 额外的加密操作...
        // 额外的缓冲操作...
    }
};

void Process() {
    // 编译时装配,在编译时就确定具体的类型
    CryptoFileStream *fs1 = new CryptoFileStream();

    BufferedFileStream *fs2 = new BufferedFileStream();

    CryptoBufferedFileStream *fs3 = new CryptoBufferedFileStream();

}
2.3.2 decorator2
// 流基类
class Stream {
public:
	// 纯虚函数
    virtual char Read(int number) = 0;
    virtual void Seek(int position) = 0;
    virtual void Write(char data) = 0;
    
    // 析构函数
    virtual ~Stream() {}
    
};

/******************** 主体类 ********************/
// 文件流类
class FileStream : public Stream {
public:
    virtual char Read(int number) {
        // 读文件流
    }
    
    virtual void Seek(int position) {
        // 定位文件流
    }
    
    virtual void Write(char data) {
        // 写文件流
    }
};

// 网络流类
class NetworkStream : public Stream {
public:
    virtual char Read(int number) {
        // 读网络流
    }
    
    virtual void Seek(int position) {
        // 定位网络流
    }
    
    virtual void Write(char data) {
        // 写网络流
    }
};

// 内存流类
class MemoryStream : public Stream {
public:
    virtual char Read(int number) {
        // 读内存流
    }
    
    virtual void Seek(int position) {
        // 定位内存流
    }
    
    virtual void Write(char data) {
        // 写内存流
    }
};

/******************** 扩展操作 ********************/
// 加密流类
class CryptoStream : public Stream {

    Stream* stream;	// ...	组合形式,Stream是个抽象类,不是一个具体的类

public:
	// 构造函数
    CryptoStream(Stream* stm) : stream(stm) {
    
    }
    
    virtual char Read(int number) {
        // 额外的加密操作...
        stream->Read(number);	// 读流
    }
    virtual void Seek(int position) {
        // 额外的加密操作...
        stream->Seek(position);	// 定位流
        // 额外的加密操作...
    }
    virtual void Write(byte data) {
        // 额外的加密操作...
        stream->Write(data);	// 写流
        // 额外的加密操作...
    }
};

// 缓冲流类
class BufferedStream : public Stream {
    
    Stream* stream;	// ...	组合形式
    
public:
    BufferedStream(Stream* stm) : stream(stm) {
        
    }
    //...
};

void Process() {

    // 运行时装配,在运行时才确认具体类型
    FileStream* s1 = new FileStream();
    CryptoStream* s2 = new CryptoStream(s1);		// s2中的stream绑定FileStream类型
    
    BufferedStream* s3 = new BufferedStream(s1);	// s3中的stream绑定FileStream类型
    
    BufferedStream* s4 = new BufferedStream(s2);	// s4中的stream绑定CryptoStream类型
}
2.3.3 decorator3
// 流基类
class Stream {
public:
	// 纯虚函数
    virtual char Read(int number) = 0;
    virtual void Seek(int position) = 0;
    virtual void Write(char data) = 0;
    
    // 析构函数
    virtual ~Stream() {}
};

/******************** 主体类 ********************/
// 文件流类
class FileStream: public Stream {
public:
    virtual char Read(int number) {
        // 读文件流
    }
    
    virtual void Seek(int position) {
        // 定位文件流
    }
    
    virtual void Write(char data) {
        // 写文件流
    }

};

// 网络流类
class NetworkStream : public Stream {
public:
    virtual char Read(int number) {
        // 读网络流
    }
    
    virtual void Seek(int position) {
        // 定位网络流
    }
    
    virtual void Write(char data) {
        // 写网络流
    }
};

// 内存流类
class MemoryStream : public Stream {
public:
    virtual char Read(int number) {
        // 读内存流
    }
    
    virtual void Seek(int position) {
        // 定位内存流
    }
    
    virtual void Write(char data) {
        // 写内存流
    }
};

/******************** 扩展操作 ********************/
// 装饰器流类
DecoratorStream : public Stream {
protected:
    Stream* stream;	// ...	组合形式,Stream是个抽象类,不是一个具体的类
    
    // 构造函数
    DecoratorStream(Stream * stm) : stream(stm) {
    
    }  
};

// 加密流类,继承装饰器流类
class CryptoStream : public DecoratorStream {
public:
	// 构造函数,调用父类的构造函数
    CryptoStream(Stream* stm) : DecoratorStream(stm) {
    
    }
    
    virtual char Read(int number) {   
        // 额外的加密操作...
        stream->Read(number);	// 读流
    }
    
    virtual void Seek(int position) {
        // 额外的加密操作...
        stream->Seek(position);	// 定位流
        // 额外的加密操作...
    }
    
    virtual void Write(byte data) {
        // 额外的加密操作...
        stream->Write(data);	// 写流
        // 额外的加密操作...
    }
};

// 缓冲流类,继承装饰器流类
class BufferedStream : public DecoratorStream {
public:
	// 构造函数,调用父类的构造函数
    BufferedStream(Stream* stm): DecoratorStream(stm) {
        
    }
    
    // ...
};

void Process(){

    // 运行时装配
    FileStream* s1 = new FileStream();
    
    CryptoStream* s2 = new CryptoStream(s1);
    
    BufferedStream* s3 = new BufferedStream(s1);
    
    BufferedStream* s4 = new BufferedStream(s2);
}

2.4 结构(Structure)

在这里插入图片描述

2.5 要点总结

  • 通过采用组合而非继承的手法,Decorator 模式实现了在运行时动态扩展对象功能的能力,而且可以根据需要扩展多个功能。避免了使用继承带来的 “灵活性差” 和 “多子类衍生问题”。
  • Decorator 类在接口上表现为is-a Component 的继承关系,即 Decorator 类继承了 Component 类所具有的接口。但在实现上又表现为has-a Component 的组合关系,即 Decorator 类又使用了另外一个 Component 类。
  • Decorator 模式的目的并非解决 “多子类衍生的多继承” 问题,Decorator 模式应用的要点在于解决 “主体类在多个方向上的扩展功能” —— 是为 “装饰” 的含义。

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

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

相关文章

Android 内存优化:什么原因导致内存问题?通过内存工具进行分析;内存抖动和内存泄漏;MAT的使用;Profiler的使用;如何优化?

目录 一、为什么要进行内存优化呢? 我们开发一个App程序,如果不了解内存的使用情况,就是将稳定性弃之不管。因为你不知道他在什么时候会发生OOM问题,不知道为什么程序会卡顿,不知道为什么会发生问题。你也没有自信跟别…

算法题之香槟塔

香槟塔 我们把玻璃杯摆成金字塔的形状,其中 第一层 有 1 个玻璃杯, 第二层 有 2 个,依次类推到第 100 层,每个玻璃杯将盛有香槟。 从顶层的第一个玻璃杯开始倾倒一些香槟,当顶层的杯子满了,任何溢出的香槟…

【TypeScript】知识点梳理(三)

#void前面提到了代表空,但有个特殊情况,是空不是空,细谈是取舍,但我们不深究hhh# 代码示例: type func () > voidconst f1: func function() {return true; } 定义了空,返回非空值,理论…

Windows搭建RTMP服务器

这里写自定义目录标题 1 Nginx-RTMP服务器搭建1.1 下载Nginx1.2 下载Nginx的RTMP扩展包1.3 配置Nginx1.4 启动Nginx1.5 查看Nginx状态 2 FFmpeg推流2.1 下载FFmpeg2.2 配置FFmpeg环境变量2.3 验证FFmpeg配置 3 视频推流3.1 OBS推流3.2 FFmpeg推流 4 VLC拉流4.1 VLC4.2 打开网络…

vue3+PPTXjs 在线ppt预览

- 使用PPTXjs做ppt预览,有完整的代码包,基于jquery - vue3使用iframe引入用于预览ppt的网页,通过url参数传递需要预览的ppt链接 - 通过网页选择文件上传也可以通过下面的函数把文件转换成链接,实现在文件上传到服务器前就可以预…

【深度强化学习】DDPG实现的4个细节(OUNoise等)

文章目录 前言一、论文内容简述创新点(特点,与DQN的区别):可借鉴参数:细节补充: 二、细节1:weight_decay原理代码 三、细节2:OUNoise原理代码 四、细节3:ObsNorm原理代码…

PostgreSQL分区表,实战细节满满

📢📢📢📣📣📣 作者:IT邦德 中国DBA联盟(ACDU)成员,10余年DBA工作经验, Oracle、PostgreSQL ACE CSDN博客专家及B站知名UP主,全网粉丝10万 擅长主流Oracle、My…

茄子病虫害数据集。四类:果肉腐烂、蛀虫、健康、黄斑病。4000张图片,已经按照8:2的比例划分好训练集、验证集 txt格式 含类别yaml文件 已经标注好

茄子病虫害数据集。可用于筛选茄子品质、质量,训练采摘机器人视觉算法模型……数据集大部分图片来源于真实果园拍摄的图片(生长在果树之上的),图片分辨率高,数据集分为四类:果肉腐烂、蛀虫、健康、黄斑病。…

如何使用ssm实现基于Java的民宿预订管理系统的设计与实现

TOC ssm773基于Java的民宿预订管理系统的设计与实现jsp 绪论 1.1课题研究背景意义 随着科技的发展,计算机的应用,人们的生活方方面面都和互联网密不可分。计算机的普及使得人们的生活更加方便快捷,网络也遍及到我们生活的每个角落&#x…

Vue - 打包部署

vscode找到NPM脚本,点击build。 目录下出现dist目录则表示安装成功。 安装Nginxnginx: download 目录用途conf配置文件目录html静态资源文件目录logs日志文件目录temp临时文件目录 将刚刚打包好的文件放到html目录下。 点击nginx.exe,用localhost:默认…

Windows应急响应-QQ巨盗病毒

文章目录 病毒背景样本分析开启监控感染病毒分析病毒行为C盘文件监控D盘文件监控进程监控排查服务排查启动项排查 查杀1.杀掉进程2.异常服务3.映像劫持处理4.hosts文件处理5.D盘文件删除6.其他异常排查 重启排查 病毒背景 简介:Win32.PSWTroj.QQPass,名…

模拟退火算法简介

什么是模拟退火算法? 模拟退火算法(Simulated Annealing,SA)是一种基于随机化搜索的优化算法,灵感来源于金属退火过程。在金属制造中,金属被加热到高温并缓慢冷却,这一过程可以减少内部缺陷&am…

【前端】-音乐播放器(源代码和结构讲解,大家可以将自己喜欢的歌曲添加到数据当中,js实现页面动态显示音乐)

前言:音乐播放器是前端开发中的一个经典项目,通过它可以掌握很多核心技术,如音频处理、DOM操作、事件监听、动画效果等。这个项目不仅能提升前端开发的技能,还能让开发者深入理解JavaScript与HTML的协同作用。 页面展示&#xff1…

精准选择大模型:消费品行业的营销与体验创新之路

在消费品行业,大模型技术的引入正逐渐从一个新兴趋势转变为行业标配。随着人工智能的快速发展,特别是OpenAI等领军企业推出的创新技术,如Sora,大模型在市场营销、消费者行为分析、个性化推荐等方面展现出巨大潜力。然而&#xff0…

基础算法(5)——位运算

1. 常见位运算总结 1) 基础位运算 2) 给一个数 n,确定它的二进制表示中的第 x 位是 0 还是 1 3) 将一个数 n 的二进制表示的第 x 位修改成 1 4) 将一个数 n 的二进制表示的第 x 位修改成 0 5) 位图的思想 位图的本质就是 哈希表 6) 提取一个数 n 二进制表示中最右…

如 有 任 何 问 题 ,请 及 时 联 系 我 们 反 馈 !

如有任何问题, 请及时联系我们反馈 !https://support.qq.com/products/671606 如有任何问题, 请及时联系我们反馈 !

Bluetooth Channel Sounding中关于CS Procedure的详细介绍

目录 BLE CS 过程定义: BLE CS 过程的组成部分 开始一个BLE CS 过程 与BLE CS过程相关的参数设置 BLE CS 过程定义: BLE 的CS特性包含一组LL层和空口协议的组合过程,该过程可以使得两个BLE 设备以紧密互锁的方式,在多个信道上…

Ubuntu 上安装 MySQL 并且实现远程登录

目录 1. 安装MySQL 2. 安全配置MySQL 3. 配置MySQL远程登录 3.1. 允许远程连接 3.2. 重启MySQL服务 3.3. 为用户分配远程访问权限 进入MySQL后,执行以下命令: 3.4. 创建新用户 3.5. 授予权限 3.6. 刷新权限 3.7. 退出 MySQL 控制台 4. 配置防火…

2024.9月29日~10月6日 SSM框架项目-《电信资费管理系统》

一、数据库介绍: 1、account:帐务信息表 2、admin_info:管理员信息表 3、admin_role:管理员角色信息表 4、cost:资费信息表 5、privilege_info:权限信息表 6、role_info:角色信息表 7、role_pri…

在CentOS7上安装mysql

目录 1.下载安装文件 2.上传到CentOS7上 3.解压MySQL文件 4.清理系统中残留的MySQL 5.安装MySQL 6.启动MySQL 并 设置开机自启动 7.查找临时密码,并修改密码 注意: 教程:在Linux上安装mysql(超详细版)_哔哩哔哩…