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

news2024/10/7 19:28:17
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.coloradmin.cn/o/1573153.html

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

相关文章

Python+Django+Html河道垃圾识别网页系统

程序示例精选 PythonDjangoHtml河道垃圾识别网页系统 如需安装运行环境或远程调试,见文章底部个人QQ名片,由专业技术人员远程协助! 前言 这篇博客针对《PythonDjangoHtml河道垃圾识别网页系统》编写代码,代码整洁,规…

【多模态融合】MetaBEV 解决传感器故障 3D检测、BEV分割任务

前言 本文介绍多模态融合中,如何解决传感器故障问题;基于激光雷达和相机,融合为BEV特征,实现3D检测和BEV分割,提高系统容错性和稳定性。 会讲解论文整体思路、模型框架、论文核心点、损失函数、实验与测试效果等。 …

961: 进制转换问

【学习版】 【C语言】 #include<iostream>struct SeqList {int top;int len;int* s; };void initStack(SeqList* stack, int len) {stack->s new int[len];stack->top -1;stack->len len; }void push(SeqList* stack, int x) {stack->s[stack->top] …

调用阿里云API接口实现电商领域命名实体识别NER

文章目录 阿里云简介命名实体识别NER阿里云API注册调用代码阿里云简介 阿里云是全球领先的云计算及人工智能科技公司,成立于2009年,为200多个国家和地区的企业、开发者和政府机构提供服务。阿里云提供了一系列的云计算服务,包括服务器租赁、云数据库、云存储、人工智能等,…

Jenkins (四) - 搭建 Docker SonarQube

Jenkins (四) - 搭建 Docker SonarQube 拉取 SonarQube $ docker pull sonarqube拉取 postgres $ $ docker pull postgres运行 postgres $ docker run -itd \ -e TZAsia/Shanghai -e POSTGRES_USERtester \ -e POSTGRES_PASSWORD123456 \ -p 5432:5432 \ -v /home/tester/d…

KK全域电商,全体系打造实操课,多平台打造电商逻辑体系

实操课详细指导分析流程 资深运营老师陪伴式答疑 课程下载&#xff1a;https://download.csdn.net/download/m0_66047725/89013409 更多资源下载&#xff1a;关注我。 课程内容&#xff1a; 1先导课(拍下请看).mp4 2为什么要做小..红营 .mp4 3小红营适合什么类目的产品,…

神经网络分类和回归任务实战

学习方法&#xff1a;torch 边用边学&#xff0c;边查边学 真正用查的过程才是学习的过程 直接上案例&#xff0c;先来跑&#xff0c;遇到什么解决什么 数据集Minist 数据集 做简单的任务 Minist 分类任务 总体代码&#xff08;可以跑通&#xff09; from pathlib import …

基于vue+node.js导师选择分配管理系统

开发语言 node.js 框架&#xff1a;Express 前端:Vue.js 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat 开发软件&#xff1a;VScode .设计一套导师选择管理系统&#xff0c;帮助学校进行导师选择管理等繁琐又重复的工作&#xff0c;提高工作效率的同时&#xff0c…

三、Jenkins相关操作

Jenkins操作 一、插件管理1.修改公共插件源2.下载中文汉化插件2.1 安装插件2.2 重启2.3 设置为中文 3.远程部署插件 二、用户权限管理1.安装权限插件2.开启权限3.创建角色3.1 Global roles3.2 Item roles 4.创建用户5.给用户分配角色 三、凭证管理四、Git管理1.账号密码方式1.1…

【智能排班系统】雪花算法生成分布式ID

文章目录 雪花算法介绍起源与命名基本原理与结构优势与特点应用场景 代码实现代码结构自定义机器标识RandomWorkIdChooseLocalRedisWorkIdChooselua脚本 实体类SnowflakeIdInfoWorkCenterInfo 雪花算法类配置类雪花算法工具类 说明 雪花算法介绍 在复杂而庞大的分布式系统中&a…

力控机器人原理及力控制实现

力控机器人原理及力控制实现 力控机器人是一种能够感知力量并具有实时控制能力的机器人系统。它们可以在与人类进行精准协作和合作时&#xff0c;将力传感技术&#xff08;Force Sensing Technology&#xff09;和控制算法&#xff08;Control Algorithm&#xff09;结合起来&a…

场景文本检测识别学习 day01(传统OCR的流程、常见的损失函数)

传统OCR的流程 传统OCR&#xff1a;传统光学字符识别常见的的模型主要包括以下几个步骤来识别文本 预处理&#xff1a;预处理是指对输入的图像进行处理&#xff0c;以提高文字识别的准确率。这可能包括调整图像大小、转换为灰度图像、二值化&#xff08;将图像转换为黑白两色&…

4.1.k8s的pod-创建,数据持久化,网络暴露,env环境变量

目录 一、Pod介绍 二、指令创建和管理Pod 三、资源清单创建pod 1.挂载hostPath存储卷 2.NFS存储卷 所有节点安装nfs k8s3编辑NFS配置文件 k8s1&#xff0c;k8s2节点开机挂载 编辑pod资源清单&#xff0c;挂载nfs 四、pod网络暴露 1.hostNetwork使用宿主机的网络 2.…

Struts2的入门:新建项目——》导入jar包——》jsp,action,struts.xml,web.xml——》在项目运行

文章目录 配置环境tomcat 新建项目导入jar包新建jsp界面新建action类新建struts.xml,用来配置action文件配置Struts2的核心过滤器&#xff1a;web.xml 启动测试给一个返回界面在struts.xml中配置以实现页面的跳转&#xff1a;result再写个success.jsp最后在项目运行 配置环境 …

实现点击用户头像或者id与其用户进行聊天(vue+springboot+WebSocket)

用户点击id直接与另一位用户聊天 前端如此&#xff1a; <template><!-- 消息盒子 --><div class"content-box" :style"contentWidth"><!-- 头像&#xff0c;用户名 --><div class"content-box-top box--flex">&l…

sqlmap(四)案例

一、注入DB2 http://124.70.71.251:49431/new_list.php?id1 这是墨者学院里的靶机&#xff0c;地址&#xff1a;https://www.mozhe.cn/ 1.1 测试数据库类型 python sqlmap.py -u "http://124.70.71.251:49431/new_list.php?id1" 1.2 测试用户权限类型 查询选…

【linux】ubuntu ib网卡驱动如何适配

本站以分享各种运维经验和运维所需要的技能为主 《python零基础入门》&#xff1a;python零基础入门学习 《python运维脚本》&#xff1a; python运维脚本实践 《shell》&#xff1a;shell学习 《terraform》持续更新中&#xff1a;terraform_Aws学习零基础入门到最佳实战 《k8…

晚枫|2024年3月总结,人生中第一次「车祸」

这个3月&#xff0c;真正做到了&#xff1a;过得紧张又刺激&#xff01; 1、第一次「车祸」 整个3月&#xff0c;凌晨1点之前没睡过觉&#xff0c;大部分时间都是2点以后睡。 从去年10月和朋友一起办Python中国的活动开始&#xff0c;就逐渐进入这种状态了。 除了本职工作因…

c# wpf LiveCharts 绑定 简单试验

1.概要 c# wpf LiveCharts 绑定 简单试验 2.代码 <Window x:Class"WpfApp3.Window2"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d"http://schem…

Python3 Ubuntu

一、安装中文输入法 1.sudo apt install ibus-sunpinyin 2.点击右上角输入法&#xff0c;然后点击加号&#xff0c;输入yin添加进来&#xff0c;最后选中输入法即可 二、安装截屏软件 1.sudo apt install gnome-screenshot 三、安装opencv-python 1.pip3 install --upgrade…