C++设计模式:装饰器模式(四)

1、定义与动机
  • 装饰器模式定义:动态(组合)地给一个对象增加一些额外的职责。就增加功能而言,Decorator模式比生成子类(继承)更为灵活(消除重复代码 & 减少子类个数)。

  • 在某些情况下我们可能会“过度地使用继承来扩展对象的功能”,由于继承为类型引入的静态特质,使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多子类的膨胀。

  • 如何使“对象功能的扩展”能够根据需要来动态地实现?同时避免“扩展功能的增多”带来的子类膨胀问题?从而使得任何“功能扩展变化”所导致的影响降到最低?

  • 装饰器模式有一个很独特的地方:不仅继承接口(is a)、还组合接口(has a);继承接口是为了重写接口实现接口的方法,组合是为了动态装入接口的其他子类,这样就可以轻松的实现功能拓展,但又不违背单一职责原则!

2、案例分析
  • C++中的文件流对象并没有Java中的那么丰富,在Java语言中存在各种各样的流对象,基类有InputStream/OutputStream、Reader/Writer等等
  • 同时派生出各种IO流类,通过不同的功能、作用、辅助分类可以分很多种:文件流、对象流、缓冲流、缓冲文件流、加密缓冲流、等等
  • 如果代码都单纯的靠继承来实现Java庞大的IO流类库,工作量是非常大的。
  • 导致工作量巨大的原因:单纯通过继承来实现,存在大量的CV代码

在这里插入图片描述

2.1、基础实现
  • 普通的实现方式就是一直继承,代码无线重复的去设计实现
  • 里氏替换原则:当继承基类或者父类的代码大量被重写时,继承失去其原本的意义,换句话说可以不需要继承。
  • 这样设计会导致继承失去其原本的意义,因为大量的代码都被重写(违背里氏替换原则)
class Stream{virtual char Read(int n) = 0;virtual void Seek(int n) = 0;virtual void Write(char data) = 0;virtual ~Stream(){}
};
/** FileStream、NetWorkStream、MemoryStream、ObjectStream...*/
class FileStream: public Stream{
public:virtual char Read(int n){// 读文件流}virtual void Seek(int n){// 定位文件流}virtual void Write(char data){// 写文件流}
};class NetWorkStream: public Stream{
public:virtual char Read(int n){// 读网络流}virtual void Seek(int n){// 定位网络流}virtual void Write(char data){// 写网络流}
};// CryptoFileStream、CryptoNetWorkStream、CryptoMemoryStream、CryptoObjectStream...
class CryptoFileStream: public FileStream{
public:virtual char Read(int n){// 加密FileStream::Read(n);// 加密}virtual void Seek(int n){// 加密FileStream::Seek(n);// 加密}virtual void Write(char data){// 加密FileStream::Write(n);// 加密}
};
class CryptoNetWorkStream: public NetWorkStream{
public:virtual char Read(int n){}virtual void Seek(int n){}virtual void Write(char data){}
};// BufferedFileStream、BufferedNetWorkStream、BufferedMemoryStream、BufferedObjectStream...
class BufferedFileStream: public FileStream{// ...
};
class BufferedNetWorkStream: public NetWorkStream{// ...
};// CryptoBufferedFileStream、CryptoBufferedNetWorkStream、CryptoBufferedMemoryStream、CryptoBufferedObjectStream...
class CryptoBufferedFileStream: public BufferedFileStream{virtual char Read(int n){// 加密// 缓存BufferedFileStream::Read(n);}virtual void Seek(int n){//...}virtual void Write(char data){//...}
};
  • 而这样编写到了后期持续的扩展,类的数量指数增长,代码量急剧上升

在这里插入图片描述

2.2、普通装饰器
  • 为了消除这些冗余的代码,可以优先考虑使用组合的形式来取代靠继承实现的这些IO流类
  • 基于上述代码,只要灵活使用多态和组合就可以省略掉很多冗余的代码
    • CryptoStream类中组合一个Stream抽象类的指针,当构造CryptoStream类时可以通过传入FileStream、NetWorkStream对象来完成动态绑定,然后CryptoFileStream、CryptoNetWorkStream…其内部所有的方法都一样(因为只是基于不同的流类套了一层加密,而具体哪个流类通过Stream抽象类接口来动态绑定),因此可以代码去重。
  • 因此这样就可以实现去重
class Stream{virtual char Read(int n) = 0;virtual void Seek(int n) = 0;virtual void Write(char data) = 0;virtual ~Stream(){}
};
/** FileStream、NetWorkStream、MemoryStream、ObjectStream...*/
class FileStream: public Stream{
public:virtual char Read(int n){// 读文件流}virtual void Seek(int n){// 定位文件流}virtual void Write(char data){// 写文件流}
};class NetWorkStream: public Stream{
public:virtual char Read(int n){// 读网络流}virtual void Seek(int n){// 定位网络流}virtual void Write(char data){// 写网络流}
};// CryptoFileStream、CryptoNetWorkStream、CryptoMemoryStream、CryptoObjectStream...
class CryptoStream: public Stream{
private:Stream *stream;             // new FileStream()、new NetWorkStream().....
public:CryptoStream(Stream *_stream): stream(_stream){}virtual char Read(int n){// 加密stream->Read(n);// 加密}virtual void Seek(int n){// 加密stream->Read(n);// 加密}virtual void Write(char data){// 加密stream->Read(n);// 加密}
};// BufferedFileStream、BufferedNetWorkStream、BufferedMemoryStream、BufferedObjectStream...
class BufferedStream: public Stream{Stream *stream;// ...
};// CryptoBufferedFileStream、CryptoBufferedNetWorkStream、CryptoBufferedMemoryStream、CryptoBufferedObjectStream...
class CryptoBufferedStream: public Stream{Stream *stream;             //....virtual char Read(int n){// 加密// 缓存}virtual void Seek(int n){//...}virtual void Write(char data){//...}
};void process()
{// 运行时装配FileStream fileStream = new FileStream();CryptoStream cryptoStream1 = new CryptoStream(new FileStream());CryptoStream cryptoStream2 = new CryptoStream(new NetWorkStream());....    CryptoBufferedStream cryptoBufferedStream = new CryptoBufferedStream(new FileStream());
}
2.3、抽象装饰器
  • 抽象装饰器就是在实现类和基类之间套了一个装饰器类
    • 装饰器类负责继承基类,通过多态的动态绑定来运行时确定加载某个类
    • 实现类通过继承装饰器类,调用装饰器类中的对象完成操作
class Stream{virtual char Read(int n) = 0;virtual void Seek(int n) = 0;virtual void Write(char data) = 0;virtual ~Stream(){}
};
/** FileStream、NetWorkStream、MemoryStream、ObjectStream...*/
class FileStream: public Stream{
public:virtual char Read(int n){// 读文件流}virtual void Seek(int n){// 定位文件流}virtual void Write(char data){// 写文件流}
};class NetWorkStream: public Stream{
public:virtual char Read(int n){// 读网络流}virtual void Seek(int n){// 定位网络流}virtual void Write(char data){// 写网络流}
};class DecoratorStream: Stream{
protected:Stream *stream;DecoratorStream(Stream *_stream): stream(_stream){}
};// CryptoFileStream、CryptoNetWorkStream、CryptoMemoryStream、CryptoObjectStream...
class CryptoStream: public DecoratorStream{
public:CryptoStream(Stream *_stream): DecoratorStream(_stream){}virtual char Read(int n){// 加密stream->Read(n);// 加密}virtual void Seek(int n){// 加密stream->Read(n);// 加密}virtual void Write(char data){// 加密stream->Read(n);// 加密}
};// BufferedFileStream、BufferedNetWorkStream、BufferedMemoryStream、BufferedObjectStream...
class BufferedStream: public DecoratorStream{// ...
};// CryptoBufferedFileStream、CryptoBufferedNetWorkStream、CryptoBufferedMemoryStream、CryptoBufferedObjectStream...
class CryptoBufferedStream: public DecoratorStream{virtual char Read(int n){// 加密// 缓存}virtual void Seek(int n){//...}virtual void Write(char data){//...}
};void process()
{// 运行时装配FileStream fileStream = new FileStream();CryptoStream cryptoStream1 = new CryptoStream(new FileStream());CryptoStream cryptoStream2 = new CryptoStream(new NetWorkStream());....CryptoBufferedStream cryptoBufferedStream = new CryptoBufferedStream(new FileStream());
}

在这里插入图片描述

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

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c++的STL(8) -- queue

queue容器概述 queue容器实现了实现了和队列相同结构的容器。 如图,队列这种结构有两端: 队首和队尾。 对于队列,我们添加数据只能从队尾添加,删除数据只能从队首删除。是一种先进先出的结构。 -- 当然读取数据也只能从队首或者队尾读取。…

Python TensorFlow 2.6 获取 MNIST 数据

Python TensorFlow 2.6 获取 MNIST 数据 2 Python TensorFlow 2.6 获取 MNIST 数据1.1 获取 MNIST 数据1.2 检查 MNIST 数据 2 Python 将npz数据保存为txt3 Java 获取数据并使用SVM训练4 Python 测试SVM准确度 2 Python TensorFlow 2.6 获取 MNIST 数据 1.1 获取 MNIST 数据 …

【数据结构】考研真题攻克与重点知识点剖析 - 第 3 篇:栈、队列和数组

前言 本文基础知识部分来自于b站:分享笔记的好人儿的思维导图与王道考研课程,感谢大佬的开源精神,习题来自老师划的重点以及考研真题。此前我尝试了完全使用Python或是结合大语言模型对考研真题进行数据清洗与可视化分析,本人技术…

IP地址证书

IP地址证书是一种专为公网IP地址颁发的数字证书,它通过建立安全的HTTPS连接来确保数据传输的加密保护。 具体来说,IP地址证书有以下功能: 1.验证身份:IP地址证书可以证明您是与特定IP地址相关的合法用户或组织。这有助于防止网络…

使用 msys2 sshd为 windows 搭建 ssh 服务器

文章目录 概要整体架构流程技术名词解释MSYS2openSSH服务器 技术细节安装 MSYS2 环境安装openSSH配置、启动SSH 小结和扩展 概要 SSH服务器在Linux下的搭建一般的文章讨论的比较多了。在Windows下,我们常用Windows的Linux子系统来搭建ssh服务器。那有没有更好更简洁…

数据挖掘|关联分析与Apriori算法详解

数据挖掘|关联分析与Apriori算法 1. 关联分析2. 关联规则相关概念2.1 项目2.2 事务2.3 项目集2.4 频繁项目集2.5 支持度2.6 置信度2.7 提升度2.8 强关联规则2.9 关联规则的分类 3. Apriori算法3.1 Apriori算法的Python实现3.2 基于mlxtend库的Apriori算法的Python实现 1. 关联分…

京东云服务器4核8G主机租用价格418元一年,1899元3年

京东云轻量云主机4核8G服务器租用价格418元一年,1899元3年,配置为:轻量云主机4C8G-180G SSD系统盘-5M带宽-500G月流量,京东云主机优惠活动 yunfuwuqiba.com/go/jd 可以查看京东云服务器详细配置和精准报价单,活动打开如…

idea开发 java web 酒店推荐系统bootstrap框架开发协同过滤算法web结构java编程计算机网页

一、源码特点 java 酒店推荐推荐系统是一套完善的完整信息系统,结合java web开发和bootstrap UI框架完成本系统 采用协同过滤算法进行推荐 ,对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式…

(西部数码)-域名注册购买实名流程

1,进入西部数码官网 输入网址 https://www.west.cn/services/domain/ 注册域名 ,域名推荐com(国际顶级域名) ,cn(国内顶级域名)。其中cn价钱比com便宜。 特别提醒: (…

【C++】引用

目录 ​编辑 1.引用概念 2.引用特性 2.1一个变量可以取多个别名,别名还可以取别名 2.2一个别名不可以对应多个变量。 ​编辑2.3 别名的地址一样: 2.4引用必须初始化,必须有个引用实体 2.5 引用不能改变指向 3 .引用的价值和意义 3.1.做参数 …

关于 QSound播放wav音频文件,播放失败“using null output device, none available” 的解决方法

若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/137264493 红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软…

【简单讲解下epoll】

🎥博主:程序员不想YY啊 💫CSDN优质创作者,CSDN实力新星,CSDN博客专家 🤗点赞🎈收藏⭐再看💫养成习惯 ✨希望本文对您有所裨益,如有不足之处,欢迎在评论区提出…

LabVIEW深度学习

目录 一、配置环境1.1、显卡选择1.2、下载显卡驱动1.3、下载并安装Anaconda1.4、配置Anaconda软件包下载服务器1.5、配置虚拟环境tf_gpu1.6、安装vscode1.7、安装tensorflow1.8、下载安装Git1.9、安装TensorFlow Object Detection API框架1.10、安装依赖的python软件包1.11、配…

包子凑数【蓝桥杯】/完全背包

包子凑数 完全背包 完全背包问题和01背包的区别就是,完全背包问题每一个物品能取无限次。 思路:当n个数的最大公约数不为1,即不互质时,有无限多个凑不出来的,即n个数都可以表示成kn,k为常数且不为1。当n个…

Vue关键知识点

watch侦听器 Vue.js 中的侦听器(Watcher)是 Vue提供的一种响应式系统的核心机制之一。 监听数据的变化,并在数据发生变化时执行相应的回调函数。 目的:数据变化能够自动更新到视图中 原理: Vue 的侦听器通过观察对象的属性&#…

Redis实战篇-集群环境下的并发问题

实战篇Redis 3.7 集群环境下的并发问题 通过加锁可以解决在单机情况下的一人一单安全问题,但是在集群模式下就不行了。 1、我们将服务启动两份,端口分别为8081和8082: 2、然后修改nginx的conf目录下的nginx.conf文件,配置反向代…

蓝桥杯杯赛之深度优先搜索优化《1.分成互质组》 《 2.小猫爬山》【dfs】【深度搜索剪枝优化】【搜索顺序】

文章目录 思想例题1. 分成互质组题目链接题目描述【解法一】【解法二】 2. 小猫爬山题目链接题目描述输入样例:输出样例:【思路】【WA代码】【AC代码】 思想 本质为两种搜索顺序: 枚举当前元素可以放入哪一组枚举每一组可以放入哪些元素 操…

天眼护航 安全无界:天通哨兵PS02—电力巡检保护的智能利器

在电力行业中,输电线路的安全稳定运行对于保障社会经济活动至关重要。然而,广阔的输电线路常常穿越复杂的地形和恶劣的自然环境,给电力巡检和保护工作带来了巨大挑战。 为了提高巡检效率和响应速度,更好地保障电力设施的安全运行…

鸿蒙OS元服务开发:【(Stage模型)学习窗口沉浸式能力】

一、体验窗口沉浸式能力说明 在看视频、玩游戏等场景下,用户往往希望隐藏状态栏、导航栏等不必要的系统窗口,从而获得更佳的沉浸式体验。此时可以借助窗口沉浸式能力(窗口沉浸式能力都是针对应用主窗口而言的),达到预…

聚能共创下一代智能终端操作系统 软通动力荣膺“OpenHarmony优秀贡献单位”

近日,由开放原子开源基金会指导,以“开源共享未来”为主题的OpenHarmony社区年会在北京成功举办。本次活动汇集OpenHarmony项目群共建单位及生态伙伴等多方力量,旨在对2023年度OpenHarmony年度开源事业全面总结的同时,吸引更多伙伴…