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

系列文章目录

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();//附加职责AAddBehavorA();}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();//附加职责BAddBehavorB();}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();//附加职责CAddBehavorC();}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();//附加职责DAddBehavorD();}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;//给装饰对象附加职责ApDec = new ConcreteDecoratorA(pCom);//给装饰对象附加职责BpDec = new ConcreteDecoratorB(pDec);//给装饰对象附加职责CpDec = new ConcreteDecoratorC(pDec);//给装饰对象附加职责DpDec = 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.mzph.cn/news/6740.shtml

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

相关文章

LiveNVR监控流媒体Onvif/RTSP功能-支持无人机、IPC等设备RTMP推流转码分发H5无插件播放也支持GB28181输出

LiveNVR支持无人机、IPC等设备RTMP推流转码分发H5无插件播放也支持GB28181输出 1、无人机推流转国标2、获取RTMP推流地址2.1、RTMP推流地址格式2.2、推流地址示例 2、设备RTMP推流3、配置拉转RTMP3.1、直播流地址格式3.2、直播流地地址示例3.3、通道配置直播流地址 4、配置级联…

深入浅出多种开发语言对接淘宝京东1688阿里巴巴等电商平台,获取实时商品详情数据API接口介绍

api接口详解大全?优秀的设计是产品变得卓越的原因设计API意味着提供有效的接口&#xff0c;可以帮助API使用者更好地了解、使用和集成&#xff0c;同时帮助人们有效地维护它每个产品都需要使用手册&#xff0c;API也不例外在API领域&#xff0c;可以将设计视为服务器和客户端之…

IDE /完整分析C4819编译错误的本质原因

文章目录 概述基本概念代码页标识符字符集和字符编码方案源字符集和执行字符集 编译器使用的字符集VS字符集配置 有何作用编译器 - 源字符集编译器 -执行字符集 Qt Creator下配置MSVC编译器参数动态库DLL字符集配置不同于可执行程序EXE总结 概述 本文将从根本原因上来分析和解…

属猴人性格及一生运势怎么样?

生肖属猴的人聪明&#xff0c;才华出众&#xff0c;是个非常会处理人际关系的生肖&#xff0c; 开朗&#xff0c;大方&#xff0c;人缘好&#xff0c;而且能说会道&#xff0c;嘴巴甜&#xff0c;也特别擅长社交&#xff0c;喜欢热闹&#xff0c; 所以属猴人不管在哪都容易受到…

数仓学习---13、报表数据导出

星光下的赶路人star的个人主页 莫见长安行乐处&#xff0c;空令岁月易蹉跎 文章目录 一、报表数据导出1.1 MySQL建库建表1.1.1 创建数据库1.1.2 创建表 1.2 数据导出1.2.1 DataX配置文件生成脚本1.2.2 编写每日导出脚本 一、报表数据导出 为方便报表应用使用数据&#xff0c;需…

Java诊断利器 Arthas-- 一款释放潜力的神器

嘿&#xff0c;你是不是对Java开发中的调试和诊断问题感到头疼&#xff1f; 别担心&#xff0c;我要告诉你一个秘密武器&#xff01;它就像是一位超级英雄&#xff0c;能够释放你的潜力&#xff0c;解决你的烦恼&#xff01;它的名字叫做Arthas&#xff0c;是一款Java诊断利器…

手写Nacos基本原理——服务注册 配置管理

手写Nacos基本原理 一、背景介绍二、 思路方案三、过程nacosService代码pom文件配置文件具体类 nacosSDK代码pom文件配置类具体类 serviceA代码pom文件配置文件具体类 serviceB代码pom文件配置文件具体类 实现效果四、总结五、升华 一、背景介绍 之前在项目开发的过程中&#…

C# List 详解五

目录 26.GetType() 27.IndexOf(T) 28.IndexOf(T, Int32) 29.IndexOf(T, Int32, Int32) 30.Insert(Int32, T) 31.InsertRange(Int32, IEnumerable) 32.LastIndexOf(T) 33.LastIndexOf(T, Int32) 34.LastIndexOf(T, Int32, Int32) …

【CAS6.6源码解析】调试Rest API接口

CAS的web层默认是基于webflow实现的&#xff0c;ui和后端是耦合在一起的&#xff0c;做前后端分离调用和调试的时候不太方便。但是好在CAS已经添加了支持Rest API的support模块&#xff0c;添加相应模块即可。 文章目录 添加依赖并重新build效果 添加依赖并重新build 具体添加…

32位Cortex-M4 MCU:LPC54607J256ET180E、LPC54605J512BD100K 180MHz嵌入式微控制器

LPC546xx 32 位微控制器(MCU) 具有丰富的外设集、极低的功耗和增强的调试功能。 LPC546xx MCU系列采用ARM Cortex-M4内核&#xff0c;可提供以太网支持&#xff0c;并设有一个TFT LCD控制器和两个CAN FD模块。LPC546xx MCU旨在提高灵活性和性能可扩展性&#xff0c;可提供高达1…

Vue3 Vite electron 开发桌面程序

Electron是一个跨平台的桌面应用程序开发框架&#xff0c;它允许开发人员使用Web技术&#xff08;如HTML、CSS和JavaScript&#xff09;构建桌面应用程序&#xff0c;这些应用程序可以在Windows、macOS和Linux等操作系统上运行。 Electron的核心是Chromium浏览器内核和Node.js…

ABAP 为N的一个数,在原来基础上浮动在-30~30

需求&#xff1a;为N的一个数&#xff0c;在原来基础上浮动在-30~30 *&---------------------------------------------------------------------* *& Report ZZZZ111 *&---------------------------------------------------------------------* *& 需求&…

【算法基础:搜索与图论】3.4 求最短路算法(Dijkstrabellman-fordspfaFloyd)

文章目录 求最短路算法总览Dijkstra朴素 Dijkstra 算法&#xff08;⭐原理讲解&#xff01;⭐重要&#xff01;&#xff09;&#xff08;用于稠密图&#xff09;例题&#xff1a;849. Dijkstra求最短路 I代码1——使用邻接表代码2——使用邻接矩阵 补充&#xff1a;稠密图和稀疏…

npm i babel-plugin-import -D之后报错

替换modules/.bin/XX文件 1.vue-cli-service #!/bin/sh basedir$(dirname "$(echo "$0" | sed -e s,\\,/,g)")case uname in*CYGWIN*) basedircygpath -w "$basedir";; esacif [ -x "$basedir/node" ]; then"$basedir/node"…

【NLP】视觉变压器与卷积神经网络

一、说明 本篇是 变压器因其计算效率和可扩展性而成为NLP的首选模型。在计算机视觉中&#xff0c;卷积神经网络&#xff08;CNN&#xff09;架构仍然占主导地位&#xff0c;但一些研究人员已经尝试将CNN与自我注意相结合。作者尝试将标准变压器直接应用于图像&#xff0c;发现在…

CAXA中.exb或者.dwg文件保存为PDF

通常CAXAZ中的文件为.exb或者.dwg格式&#xff0c;我们想打印或者保存为PDF文件格式&#xff0c;那么就用一下的方法&#xff1a; CAXA文件如图所示&#xff1a; 框选出你要打印的图纸&#xff01;&#xff01;&#xff01;&#xff01; 我们选择"菜单"->"…

【算法基础:搜索与图论】3.5 求最小生成树算法(PrimKruskal)

文章目录 最小生成树介绍朴素Prim算法算法思路⭐例题&#xff1a;858. Prim算法求最小生成树 Kruskal算法算法思路⭐例题&#xff1a;859. Kruskal算法求最小生成树 最小生成树介绍 最小生成树 有关树的定义 生成子图&#xff1a;生成子图是从原图中选取部分节点以及这些节点…

Keepalived热备、Keepalived+LVS、HAProxy监控及后端服务器健康检查、负载均衡调度器对比

day02 day02KeepAlived高可用集群配置高可用的web集群监控本机80端口&#xff0c;实现主备切换实现原理实施配置高可用、负载均衡的web集群配置高可用、负载均衡HAProxy配置haproxy负载均衡调度器比较LVS&#xff08;Linux Virtual Server&#xff09;NginxHAProxy KeepAlive…

Pytorch个人学习记录总结 08

目录 神经网络-搭建小实战和Sequential的使用 版本1——未用Sequential 版本2——用Sequential 神经网络-搭建小实战和Sequential的使用 torch.nn.Sequential的官方文档地址&#xff0c;模块将按照它们在构造函数中传递的顺序添加。代码实现的是下图&#xff1a; 版本1—…

16_LinuxLCD驱动

目录 Framebuffer设备 LCD驱动简析 LCD驱动程序编写 LCD屏幕参数节点信息修改 LCD 屏幕背光节点信息 使能Linux logo显示 设置LCD作为终端控制台 Framebuffer设备 先来回顾一下裸机的时候LCD驱动是怎么编写的,裸机LCD驱动编写流程如下: 1.初始化I.MX6U的eLCDIF控制器,…