结构型设计模式之装饰器模式【设计模式系列】

系列文章目录

C++技能系列
Linux通信架构系列
C++高性能优化编程系列
深入理解软件架构设计系列
高级C++并发线程编程
设计模式系列

期待你的关注哦!!!
在这里插入图片描述

现在的一切都是为将来的梦想编织翅膀,让梦想在现实中展翅高飞。
Now everything is for the future of dream weaving wings, let the dream fly in reality.

结构型设计模式之装饰器模式

  • 系列文章目录
  • 一、装饰器模式介绍
  • 二、装饰器模式优缺点
    • 2.1 优点
    • 2.2 缺点
  • 三、装饰器模式使用场景
  • 四、装饰器模式实现
  • 五、装饰器模式应用案例

一、装饰器模式介绍

⚠️ 意图:
动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。

⚠️ 主要解决:
一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。

⚠️ 何时使用:
在不想增加很多子类的情况下扩展类。

⚠️ 如何解决:
将具体功能职责划分,同时继承装饰者模式。

在这里插入图片描述

图1_1 装饰器模式类图

装饰模式的特点:

  • 装饰对象和真实对象有相同的接口。客户端对象可以使用和真实对象相同的方式和装饰对象交互。

  • 装饰对象包含一个真实对象的索引(reference)

  • 装饰对象接受所有的来自客户端的请求,并把请求转发给真实的对象。

  • 装饰对象可以在转发来自客户端的请求以前或以后增加一些附加功能。可以确保在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常通过继承来实现对给定类的功能扩展。通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法。但继承是静态的,用户不能控制增加行为的方式和时机。如果希望改变一个已经初始化的对象的行为,则只能在于运行时完成;如果希望继承许多类的行为,则可能会导致产生大量的不同的类。

    装饰模式提供了改变子类的灵活方案。装饰模式在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能,实际上时通过创建一个包装对象(装饰),来包裹真实的对象。

    当用于一组子类时,装饰模式更加有用。如果拥有一族子类(从一个父类派生而来),需要在与子类独立使用情况下添加额外的特性,可以使用装饰模式,以避免代码重复和具体子类数量的增加。

二、装饰器模式优缺点

2.1 优点

  • 比静态继承更灵活。与对象的静态继承(多重继承)相比,装饰模式提供了更加灵活的向对象添加职责的方式。可以用添加和分离的方法,用装饰在运行时刻增加和删除职责。继承机制要求为每个添加的职责创建一个新的子类,会产生许多新的类,并且会增加系统的复杂度。此外,为一个特定的Component类提供多个不同的 Decorator类,这就使得可以对一些职责进行混合和匹配。使用Decorator模式可以很容易地重复添加一个特性。

  • 避免在层次结构高层的类有太多的特征。装饰模式提供了一种“即用即付”的方法来添加职责,并不试图在一个复杂的可定制的类中支持所有可预见的特征。相反,可以定义一个简单的类,并且用Decorator类给简单类逐渐地添加功能,从简单的部件组合出复杂的功能。

  • 把类的装饰功能从类中搬移去除,可以简化原有的类。

  • 有效地把类的核心职责和装饰功能区分开来,而且可以去除相关类中重复的装饰逻辑。

    建造者模式要求建造的过程必须是稳定的,而装饰模式的建造过程是不稳定的,可以有各种各样的组合方式。

2.2 缺点

  • Decorator与Component不一样。Decorator是一个透明的包装。如果从对象标识的观点出发,一个被装饰的组件与组件本身是有差别的,因此,使用装饰不应该依赖对象标识。

  • 有许多小对象。采用Decorator模式进行系统设计往往会产生许多类似的小对象,这些对象仅仅在他们相互连接的方式上有所不同,而不是它们的类或是它们的属性值有所不同。尽管对于那些了解这些系统的人来说,很容易对它们进行定制,但是很难学习这些系统,排错也很困难。

三、装饰器模式使用场景

  • 在不影响其他对象的情况下,以动态,透明的方式给单个对象添加职责。

  • 处理那些可以撤销的职责

  • 当不能采用生成子类的方法扩充时。一种情况是可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

四、装饰器模式实现

Component抽象类:

#ifndef COMPONENT_H
#define COMPONENT_H
#include <iostream>
using namespace std;
 
//Component抽象类,定义类对象的接口
class Component
{
public:
    virtual ~Component(){}
    virtual void Operation() = 0;
protected:
    Component(){}
};
 
#endif // COMPONENT_H

ConcreteComponent具体对象类:

#ifndef CONCRETECOMPONENT_H
#define CONCRETECOMPONENT_H
#include "Component.h"
 
//ConcreteComponent:具体的Component对象,可以给对象动态添加职责
class ConcreteComponent : public Component
{
public:
    ConcreteComponent(){}
    ~ConcreteComponent(){}
    virtual void Operation()
    {
        cout << "Original:ConcreteComponent::Operation" << endl;
    }
};
 
#endif // CONCRETECOMPONENT_H

Decorator抽象装饰对象类:

#ifndef DECORATOR_H
#define DECORATOR_H
#include "Component.h"
 
//Decorator:装饰抽象类,继承自Component
class Decorator : public Component
{
public:
    Decorator(Component* com)
    {
        m_pCom = com;
    }
    void setComponent(Component* com)
    {
        m_pCom = com;
    }
    virtual ~Decorator(){}
    virtual void Operation() = 0;
protected:
    Component* m_pCom;
};
 
#endif // DECORATOR_H

ConcreteDecoratorA具体装饰对象类:

#ifndef CONCRETEDECORATORA_H
#define CONCRETEDECORATORA_H
#include "Decorator.h"
 
//ConcreteDecorator就是具体的装饰对象,起到给Component添加职责的功能
class ConcreteDecoratorA : public Decorator
{
public:
    ConcreteDecoratorA(Component* com):Decorator(com)
    {
    }
    ~ConcreteDecoratorA(){}
    virtual void Operation()
    {
        m_pCom->Operation();
        //附加职责A
        AddBehavorA();
    }
    void AddBehavorA()
    {
        cout << "Extra A:ConcreteDecoratorA::AddBehavorA" << endl;
    }
};
 
#endif // CONCRETEDECORATORA_H

ConcreteDecoratorB具体装饰对象类:

#ifndef CONCRETEDECORATORB_H
#define CONCRETEDECORATORB_H
#include "Decorator.h"
 
//ConcreteDecorator就是具体的装饰对象,起到给Component添加职责的功能
class ConcreteDecoratorB : public Decorator
{
public:
    ConcreteDecoratorB(Component* com):Decorator(com)
    {}
    ~ConcreteDecoratorB(){}
    virtual void Operation()
    {
        m_pCom->Operation();
        //附加职责B
        AddBehavorB();
    }
    void AddBehavorB()
    {
        cout << "Extra B:ConcreteDecoratorB::AddBehavorB" << endl;
    }
};
 
#endif // CONCRETEDECORATORB_H

ConcreteDecoratorC具体装饰对象类:

#ifndef CONCRETEDECORATORC_H
#define CONCRETEDECORATORC_H
#include "Decorator.h"
 
//ConcreteDecorator就是具体的装饰对象,起到给Component添加职责的功能
class ConcreteDecoratorC : public Decorator
{
public:
    ConcreteDecoratorC(Component* com):Decorator(com)
    {}
    ~ConcreteDecoratorC(){}
    virtual void Operation()
    {
        m_pCom->Operation();
        //附加职责C
        AddBehavorC();
    }
    void AddBehavorC()
    {
        cout << "Extra C:ConcreteDecoratorC::AddBehavorC" << endl;
    }
};
 
#endif // CONCRETEDECORATORC_H

ConcreteDecoratorD具体装饰对象类:

#ifndef CONCRETEDECORATORD_H
#define CONCRETEDECORATORD_H
#include "Decorator.h"
 
//ConcreteDecorator就是具体的装饰对象,起到给Component添加职责的功能
class ConcreteDecoratorD : public Decorator
{
public:
    ConcreteDecoratorD(Component* com):Decorator(com)
    {}
    ~ConcreteDecoratorD(){}
    virtual void Operation()
    {
        m_pCom->Operation();
        //附加职责D
        AddBehavorD();
    }
    void AddBehavorD()
    {
        cout << "Extra D:ConcreteDecoratorD::AddBehavorD" << endl;
    }
};
 
#endif // CONCRETEDECORATORD_H

客户调用程序:

#include "ConcreteComponent.h"
#include "ConcreteDecoratorA.h"
#include "ConcreteDecoratorB.h"
#include "ConcreteDecoratorC.h"
#include "ConcreteDecoratorD.h"
 
int main()
{
    //要装饰的对象
    Component* pCom = new ConcreteComponent();
    Decorator* pDec = NULL;
     //给装饰对象附加职责A
    pDec = new ConcreteDecoratorA(pCom);
     //给装饰对象附加职责B
    pDec = new ConcreteDecoratorB(pDec);
     //给装饰对象附加职责C
    pDec = new ConcreteDecoratorC(pDec);
     //给装饰对象附加职责D
    pDec = new ConcreteDecoratorD(pDec);
    pDec->Operation();
 
    delete pCom,pDec;
    return 0;
}

五、装饰器模式应用案例

手机装饰实例:

Phone抽象类:

#ifndef PHONE_H
#define PHONE_H
#include <iostream>
#include <string>
using namespace std;
 
//抽象类
class Phone
{
public:
    Phone(){}
    virtual ~Phone(){}
    virtual void showDecorator() = 0;
};
 
#endif // PHONE_H

iPhone具体对象类:

#ifndef IPHONE_H
#define IPHONE_H
#include "Phone.h"
 
//具体手机类
class iPhone : public Phone
{
public:
    iPhone(string name):m_name(name){}
    ~iPhone(){}
    void showDecorator()
    {
        cout << m_name << " 's Decorator" << endl;
    }
private:
    string m_name;
};
 
#endif // IPHONE_H

MiPhone具体对象类:

#ifndef MIPHONE_H
#define MIPHONE_H
#include "Phone.h"
 
//具体手机类
class MiPhone : public Phone
{
public:
    MiPhone(string name):m_name(name){}
    ~MiPhone(){}
    void showDecorator()
    {
        cout << m_name << " 's Decorator" << endl;
    }
private:
    string m_name;
};
 
#endif // MIPHONE_H

DecoratorPhone装饰基类:

#ifndef DECORATORPHONE_H
#define DECORATORPHONE_H
#include "Phone.h"
 
//装饰基类
class DecoratorPhone : public Phone
{
public:
    DecoratorPhone(Phone* phone):m_phone(phone){}
    ~DecoratorPhone(){}
    virtual void showDecorator() = 0;
protected:
    Phone* m_phone;//要装饰的对象
};
 
#endif // DECORATORPHONE_H

DecoratorPhoneA具体装饰对象类:

#ifndef DECORATORPHONEA_H
#define DECORATORPHONEA_H
#include "DecoratorPhone.h"
 
//具体装饰类
class DecoratorPhoneA : public DecoratorPhone
{
public:
    DecoratorPhoneA(Phone* phone):DecoratorPhone(phone){}
    void showDecorator()
    {
        m_phone->showDecorator();
        addDecorator();//增加装饰
    }
private:
    void addDecorator()
    {
        cout << "add a DecoratorPhoneA Decorator" << endl;
    }
};
 
#endif // DECORATORPHONEA_H

DecoratorPhoneB具体装饰对象类:

#ifndef DECORATORPHONEB_H
#define DECORATORPHONEB_H
#include "DecoratorPhone.h"
 
//具体装饰类
class DecoratorPhoneB : public DecoratorPhone
{
public:
    DecoratorPhoneB(Phone* phone):DecoratorPhone(phone){}
    void showDecorator()
    {
        m_phone->showDecorator();
        addDecorator();//增加装饰
    }
private:
    void addDecorator()
    {
        cout << "add a DecoratorPhoneB Decorator" << endl;
    }
};
 
#endif // DECORATORPHONEB_H

客户调用程序:

#include "Phone.h"
#include "MiPhone.h"
#include "iPhone.h"
#include "DecoratorPhoneA.h"
#include "DecoratorPhoneB.h"
 
int main()
{
    Phone *iphone = new iPhone("iPhone X");
    Phone* decorator1 = NULL;
    decorator1 = new DecoratorPhoneA(iphone); //增加装饰
    decorator1 = new DecoratorPhoneB(decorator1);    //增加装饰
    decorator1->showDecorator();//显示装饰
 
    Phone *mi = new MiPhone("Mi 6");
    Phone* decorator2 = NULL;
    decorator2 = new DecoratorPhoneA(mi); //增加装饰
    decorator2 = new DecoratorPhoneB(decorator2);//增加装饰
    decorator2->showDecorator();//显示装饰
    delete decorator2,decorator2;
    delete iphone,mi;
    return 0;
}

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

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

相关文章

如何在Windows上恢复已删除的文件?

大多数人在无意中删除了一些重要文件后无法恢复。这些文件被暂时删除&#xff0c;直到我们清空回收站才会消失。你可以通过右键单击回收站中的文件并选择还原选项来轻松恢复这些文件。但是&#xff0c;如果你清理回收站删除了文件怎么办&#xff1f;或者不小心使用Shift Delet…

SpringCloud学习路线(10)——分布式搜索ElasticSeach基础

一、初识ES &#xff08;一&#xff09;概念&#xff1a; ES是一款开源搜索引擎&#xff0c;结合数据可视化【Kibana】、数据抓取【Logstash、Beats】共同集成为ELK&#xff08;Elastic Stack&#xff09;&#xff0c;ELK被广泛应用于日志数据分析和实时监控等领域&#xff0…

【数据挖掘】将NLP技术引入到股市分析

一、说明 在交易中实施的机器学习模型通常根据历史股票价格和其他定量数据进行训练&#xff0c;以预测未来的股票价格。但是&#xff0c;自然语言处理&#xff08;NLP&#xff09;使我们能够分析财务文档&#xff0c;例如10-k表格&#xff0c;以预测股票走势。 二、对自然语言处…

2023年Q2京东环境电器市场数据分析(京东数据产品)

今年Q2&#xff0c;环境电器市场中不少类目表现亮眼&#xff0c;尤其是以净水器、空气净化器、除湿机等为代表的环境健康电器。此外&#xff0c;像冷风扇这类具有强季节性特征的电器也呈现出比较好的增长态势。 接下来&#xff0c;结合具体数据我们一起来分析Q2环境电器市场中…

【已解决】jupyter notebook里已经安装了第三方库,还是提示导入失败

在jupyter notebook中运行Python代码&#xff0c;明明已经安装了第三方库&#xff0c;还是提示导入失败。 以导入pandas库为例&#xff0c;其他库同理&#xff1a; 报错代码&#xff1a; import pandas报错原因&#xff1a; 电脑上存在多个python运行环境&#xff08;比如&a…

JavaEE——Spring中存取Bean的注解

目录 一、存储Bean对象 1、定义 2、存储方式 &#xff08;1&#xff09;、类注解 【1】、Controller&#xff08;控制器存储&#xff09; 【2】、Service&#xff08;服务存储&#xff09; 【3】、Repository&#xff08;仓库存储&#xff09; 【4】、Component&#xf…

[JAVAee]线程安全

目录 线程安全的理解 线程不安全的原因 ①非原子性 ②可见性 ③代码重排序 体会何为不安全的线程 保证线程安全 一个代码在多线程的环境下就很容易出现错误. 线程安全的理解 线程安全是什么呢?通俗的来讲,线程安全就是在多线程的环境下,代码的结果是符合我们预期的,就…

Kafka基础架构与核心概念

Kafka简介 Kafka是由Apache软件基金会开发的一个开源流处理平台&#xff0c;由Scala和Java编写。Kafka是一种高吞吐量的分布式发布订阅消息系统&#xff0c;它可以处理消费者在网站中的所有动作流数据。架构特点是分区、多副本、多生产者、多订阅者&#xff0c;性能特点主要是…

VisualStudio如何进行插件开发?

文章目录 0.引言1.工具准备2.创建插件项目&#xff08;VSIX&#xff09;3.自定义VSIX属性4.创建一个command命令5.设置command名称6.编写command功能7.调试插件8.安装插件 0.引言 使用Visual Studio插件可以极大地提升开发效率、提供更好的集成环境、丰富扩展生态系统、方便调试…

python报错:‘unicodeescape‘ codec can‘t decode bytes解决办法

参考:https://blog.csdn.net/shuyudexiaowu/article/details/108771481 我的代码是这样&#xff1a; 错误原因是&#xff1a;python把字符串中的反斜杠“ \ ”当成了字符串的一部分&#xff0c;而不是反斜杠。 解决办法两个&#xff1a; 1、在文件目录前加个 r&#xff0c;&…

线性神经网路——线性回归随笔【深度学习】【PyTorch】【d2l】

文章目录 3.1、线性回归3.1.1、PyTorch 从零实现线性回归3.1.2、简单实现线性回归 3.1、线性回归 线性回归是显式解&#xff0c;深度学习中绝大多数遇到的都是隐式解。 3.1.1、PyTorch 从零实现线性回归 %matplotlib inline import random import torch #d2l库中的torch模块&a…

PCL 计算点云AABB包围盒

目录 一、算法原理二、代码实现1、直接计算2、惯性矩法三、结果展示本文由CSDN点云侠原创。爬虫自重,把自己当个人。 一、算法原理 AABB包围盒又称了 轴对齐包围盒,是点云包围盒里最简单的一种,其计算方法也极其简单,看代码即可理解!!!目前PCL中有直接计算和基于惯性偏…

Xshell使用sftp传输文件

单击工具栏新建回话图标&#xff0c;在弹出的新建回话窗口中协议选择SFTP&#xff0c;输入主机名或ip地址&#xff0c;端口号22&#xff0c;单击连接&#xff0c;输入用户名和密码完成创建连接。 本地/远程目录设置&#xff1a;新建会话时在下图中SFTP中设置文件上传下载的本地…

TOOD Task-aligned One-stage Object Detection 论文学习

1. 解决了什么问题&#xff1f; 目标检测通过多任务学习的方式&#xff0c;协同优化目标的分类和定位。分类任务会学习目标的判别特征&#xff0c;关注于目标的显著性或关键区域&#xff0c;而定位任务则学习准确地定位目标的边界。因为定位和分类的学习机制不同&#xff0c;这…

DP学习第三篇之不同路径

DP学习第三篇之不同路径 62. 不同路径 - 力扣&#xff08;LeetCode&#xff09; 一.题目解析 二. 算法原理 状态表示 tips: 经验题目要求。以[i,j]位置为结尾&#xff0c;。。。 dp[i][j]: 走到[i, j]位置时&#xff0c;一共多少种路径 状态转移方程 tips: 用之前或之后的状…

Visual Studio Code安装详细教程

win电脑可以打开该网址 vs官方下载网站 点击这里免费下载 下载下来是一个安装程序&#xff0c;直接以管理员身份运行即可 我同意安装&#xff0c;然后选择D盘的一个空间进行安装 然后点击下一步 安装如图所示勾选&#xff0c;点击下一步 点击安装 等待安装完成即可 打开…

Electron 学习_BrowserWindow

BrowserWindow创建并控制浏览器窗口(主进程) 条件&#xff1a;在 app 模块 emitted ready 事件之前&#xff0c;您不能使用此模块。 1.在加载页面时&#xff0c;渲染进程第一次完成绘制时&#xff0c;如果窗口还没有被显示&#xff0c;渲染进程会发出 ready-to-show 事件 。 在…

前端(九)——探索微信小程序、Vue、React和Uniapp生命周期

&#x1f642;博主&#xff1a;小猫娃来啦 &#x1f642;文章核心&#xff1a;探索微信小程序、Vue、React和Uniapp生命周期 文章目录 微信小程序、Vue、React和Uniapp的基本定义和应用领域微信小程序生命周期生命周期概述页面生命周期应用生命周期组件和API的生命周期钩子 Vu…

失去中国市场的三星继续称霸全球,中国手机的份额反而进一步下降了

市调机构canalys公布了二季度全球手机市场的数据&#xff0c;数据显示三星、苹果的市场份额保持稳定并位居全球前二&#xff0c;三星的表现显然让人称奇&#xff0c;一直被唱衰&#xff0c;却一直都稳稳占据全球手机市场第一名。 从Canalys公布的数据可以看到&#xff0c;三星以…

从零开始学习自动驾驶路径规划-环境配置

从零开始学习自动驾驶路径规划-环境配置 前面&#xff0c;每个人遇到的问题不一样&#xff0c;这里记录了配置步骤和目前遇到的问题&#xff0c;会持续更新报错解决方法。配置时有报错请认真看报错经验 环境配置步骤&#xff08;18.04和20.04都可以&#xff0c;有些问题没遇到…