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

news2024/12/28 20:35:50

系列文章目录

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;
}

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

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

相关文章

上海科技大学智能生活组齐聚合合信息,“沉浸式”体验人工智能产品

近期&#xff0c;上海科技大学组织本科生产业实践-校企联合人才培养活动&#xff0c;30余名学生组成的“智能生活组”实地参访人工智能及大数据科技企业上海合合信息科技股份有限公司&#xff08;简称“合合信息”&#xff09;。本次活动旨在通过项目体验、主题交流&#xff0c…

2023-7-24-第二十二式备忘录模式

&#x1f37f;*★,*:.☆(&#xffe3;▽&#xffe3;)/$:*.★* &#x1f37f; &#x1f4a5;&#x1f4a5;&#x1f4a5;欢迎来到&#x1f91e;汤姆&#x1f91e;的csdn博文&#x1f4a5;&#x1f4a5;&#x1f4a5; &#x1f49f;&#x1f49f;喜欢的朋友可以关注一下&#xf…

VS Code 设置大小写转换快捷键

VS Code 设置大小写转换快捷键 前言&#xff1a;VS Code 没有默认的大小写转换快捷键&#xff0c;需要我们自己添加。 一 、打开快捷键设置面板 二、添加快捷键 在搜索框输入 “转换为大写”&#xff0c;如果您的VS Code没有汉化&#xff0c;此处输入“Transform to Uppercase…

vmware平台上虚拟机无法查看到WWID

需要在虚拟机中部署rac测试环境&#xff0c;创建虚拟机后无法查看到wwid [rootdb1 ~]# for i in cat /proc/partitions |awk {print $4} |grep sd; do echo "Device: $i WWID: /usr/lib/udev/scsi_id --page0x83 --whitelisted --device/dev/$i "; done |sort -k4 De…

Bootstrap每天必学之面板

Bootstrap每天必学之面板 1、面板 面板&#xff08;Panels&#xff09;是Bootstrap框http://架新增的一个组件&#xff0c;其主要作用就是用来处理一些其他组件无法完成的功能。同样在不同的版本中具有不同的源码&#xff1a; ☑ Less版本&#xff1a;对应的源码文件是 panel…

深度学习论文分享(五)DDFM: Denoising Diffusion Model for Multi-Modality Image Fusion

深度学习论文分享&#xff08;五&#xff09;DDFM: Denoising Diffusion Model for Multi-Modality Image Fusion 前言Abstract1. Introduction2. Background2.1. Score-based diffusion models2.2. Multi-modal image fusion2.3. Comparison with existing approaches 3. Meth…

解决ros-melodic-desktop-full(18.04)安装过程中未满足的依赖关系问题(注:也可以解决20.04noetic的)

自己安装火焰截图软件时使用sudo apt-get install flameshot时出现&#xff1a; 正在读取软件包列表... 完成 正在分析软件包的依赖关系树 正在读取状态信息... 完成 您也许需要运行“apt --fix-broken install”来修正上面的错误。 下列软件包有未满足的依赖关系&#xff1a;…

Vue组件通信原理及应用场景解析

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

SolidWorks打开step.格式文件提示“输入的文件名无效、无法发现、被锁住或为不兼容的类型”的解决办法

有时候用SolidWorks打开step.格式文件会提示“输入的文件名无效、无法发现、被锁住或为不兼容的类型”&#xff0c;从而无法正常打开此文件&#xff0c;如图&#xff1a; 目前小编找了两种解决这个问题的办法&#xff0c;供大家参考&#xff1a; 方法一&#xff1a; 打开Solid…

istio安装部署总结

istio安装部署总结 大纲 istio基础概念版本选择安装istio核心主件卸载istiokiali安装 istio基础概念 https://istio.io/latest/zh/docs/ 中文文档 istio是一个服务治理平台&#xff0c;治理服务间的访问&#xff0c;&#xff08;例如流量控制&#xff0c;安全策略&#xf…

第五讲:MySQL中DDL表的修改与删除

1、alter&#xff1a;改变 2、table&#xff1a;表 3、truncate&#xff1a;截断&#xff0c;删节 学习渠道&#xff1a;黑马程序员

如何创建高级 CSS 下拉菜单

效果展示 实现思路及部分代码 1、定义整体页面结构 从上述的效果展示图可以看出&#xff0c;页面的整体结构应该需要一个总菜单容器来装载父级菜单项&#xff0c;并且对应的父级菜单项应该有对应的菜单子项。子菜单是分类的话&#xff0c;我们还需要额外在扩展对应的容器来装…

mysql(由浅到深)

文章目录 1. 数据库分类与SQL分类2. SQL的数据类型3. DDL CURD3.1 库的操作3.2 表约束3.3 表的操作 4 DML CURD5. DQL &#xff08;数据查询语言&#xff09;5.1 单表查询5.2 聚合查询与分组查询5.3 多表查询与外键约束5.4 多表之间的连接查询5.4.1左链接查询5.4.2 右连接查询5…

FPGA图像处理仿真实验——均值滤波(FIFO)

之前的博客中用shift ram做的均值滤波&#xff0c;那篇文章里讲了原理&#xff0c;在这里不进行重复。考虑到shift ram的深度有限&#xff0c;在处理高分辨率图片时可能会收到限制&#xff0c;所以这次采用FIFO来进行均值滤波。FIFO可以看成是一个先进先出的堆栈&#xff0c;有…

TSINGSEE视频监控汇聚平台EasyCVR视频监控录像的3种方式

视频监控综合管理平台EasyCVR可以实现海量资源的接入、汇聚、计算、存储、处理等&#xff0c;平台具备轻量化接入能力&#xff0c;可支持多协议方式接入&#xff0c;包括主流标准协议GB28181、RTSP/Onvif、RTMP等&#xff0c;以及厂家私有协议与SDK接入&#xff0c;包括海康Eho…

UE5 关于MRQ渲染器参数

最佳参数&#xff1a; Spatial Sample Count&#xff1a;使用奇数样本时临时抗锯齿会收敛 Temporal Sample Count&#xff1a;超过2之后&#xff0c;采样过大会造成TAA效果不佳 TSR&#xff1a;UE5最好的抗锯齿方案

【C#】并行编程实战:使用 Visual Studio 调试任务

并行编程可以提高应用程序的性能&#xff0c;但是调试起来会更困难&#xff0c;这一点在之前的章节中我们已经有了很直观的感受。对于程序而言&#xff0c;保证程序的正确性和保证性能同样重要。 本章将介绍可以在 Visual Studio 中的调试工具&#xff08;包括 Thread 窗口、Ta…

C#winform中Icon图标获取方式

文章目录 图标来源格式转换 图标来源 阿里巴巴矢量图库 以“文件夹”图标为例&#xff1a; 格式转换 想要给winform的窗口添加一个图标&#xff0c;可以看到&#xff0c;需要添加.ico的格式。 将上面下载的图标通过wps的图片查看器打开&#xff1a; 点击左上角的属性&…

Docker 的数据管理和镜像的创建(Dockerfile)

目录 一&#xff1a;Docker 的数据管理 1&#xff0e;数据卷 2&#xff0e;数据卷容器 3.容器互联&#xff08;使用centos镜像&#xff09; 二&#xff1a;Docker 镜像的创建 1&#xff0e;基于现有镜像创建 &#xff08;1&#xff09;首先启动一个镜像&#xff0c;在容器里…

什么是AI和BI?

近日在冲浪时看到一个问题&#xff0c;说“AI和BI都有I&#xff0c;那这两个是一个东西吗&#xff1f;”&#xff0c;想要解答一下发现无从下口&#xff0c;这一下激起了我的“求知欲”&#xff0c;于是我找了一些资料后决定写下这篇文章&#xff0c;打算从几个方面为大家解答一…