大话设计模式解读03-装饰模式

本篇文章,来解读《大话设计模式》的第6章——装饰模式。并通过C++代码实现实例代码的功能。

注:第3~6章讲的是设计模式中的一些原则(第3章:单一职责原则;第4章:开放-封闭原则;第5章:依赖倒转原则和里氏替换原则),这些原则在设计模式中用到时会提及,暂不做专门解读。

1 装饰器模式

装饰模式,或称装饰器模式(Decorator),动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更加灵活

我们在给对象增加功能时,一种做法是再设计一个子类来继续父类,然后给子类添加额外的功能,另一种做法就是通过装饰模式,设计单独用于装饰功能的类,通过“包装”的形式动态给某个对象增加功能。

2 穿搭衣服实例

题目:用控制台程序,写可以给人搭配衣服的代码

2.1 版本一

版本一的代码,仅定义了一个Person类,提供6种不同服饰的装扮接口,以及1个名字展示接口。

2.1.1 Person类

Person类的代码如下,维护一个人的名字,然后是6种服饰的穿衣接口,就是加一句打印,最后Show接口显示人的名字。

class Person
{
public:Person(std::string name){m_name = name;}void WearTShirts(){printf("大T恤 ");}void WearBigTrouser(){printf("垮裤 ");}void WearSneakrs(){printf("破球鞋 ");}void WearSuit(){printf("西装 ");}void WearTie(){printf("领带 ");}void WearLeatherShoes(){printf("皮鞋 ");}void Show(){printf("装扮的%s", m_name.c_str());}  private:std::string m_name;
};

2.1.2 主函数

主函数的逻辑如下,先实例化一个名为"小菜"的Person对象,然后依次调用穿衣接口,最后调用展示接口:

#include <iostream>int main()
{Person xc = Person("小菜");printf("\n第一种装扮:");xc.WearTShirts();xc.WearBigTrouser();xc.WearSneakrs();xc.Show();printf("\n第二种装扮:");xc.WearSuit();xc.WearTie();xc.WearLeatherShoes();xc.Show(); printf("\n");  return 0;
}

代码运行效果如下:

版本一这种方式,虽然功能实现了,但如果想要增加装扮,就需要修改Person类了,这违反了面向对象设计中的开放-封闭原则。

开放-封闭原则:是指软件实体(类、模块、函数等等)应该可以扩展,但是不可修改。

换句话说:

  • 开放:对扩展开放,当需要增加新功能时,通过代码扩展的方式(如增加新的类)实现
  • 封闭:对修改封闭,当需要增加新功能时,尽量避免对原有代码的修改

下面来看版本二如何实现。

2.2 版本二

版本二是将各种服饰单独封装了起来,并继承自服饰抽象类,将服饰类与人类进行了分离,类图如下:

这样,后续需要增加服饰时,只需要增加对应的具体服饰类,而不会影响其它已有的服饰类的代码。

2.2.1 Person类与服饰类

Person类与服饰类的代码如下,Person类只维护一个人的名字,并通过Show接口显示人的名字。服饰类的Show接口用于显示服饰的名称,具体显示的内容由具体服饰类的Show接口实现,也是打印出服饰的名字。

// Person类
class Person
{
public:Person(std::string name){m_name = name;}void Show(){printf("装扮的%s", m_name.c_str());}    private:std::string m_name;
};// 服饰类
class Finery
{
public:virtual void Show(){};
};// 各种服饰子类
class TShirts : public Finery
{
public:void Show(){printf("大T恤 ");}    
};class BigTrouser : public Finery
{
public:void Show(){printf("垮裤 ");}    
};class Sneakrs : public Finery
{
public:void Show(){printf("破球鞋 ");}    
};class Suit : public Finery
{
public:void Show(){printf("西装 ");}    
};class Tie : public Finery
{
public:void Show(){printf("领带 ");}    
};class LeatherShoes : public Finery
{
public:void Show(){printf("皮鞋 ");}    
};

2.2.2 主函数

主函数的逻辑如下,先实例化一个名为"小菜"的Person对象,

然后依次实例化具体要装扮的服饰类并调用对应的展示接口,

最后调用Person的展示接口:

int main()
{Person xc = Person("小菜"); //先实例化一个名为"小菜"的Person对象printf("\n第一种装扮:");TShirts dtx; //依次实例化具体要装扮的服饰类BigTrouser kk;Sneakrs pqx;dtx.Show(); //调用对应的展示接口kk.Show();pqx.Show();xc.Show(); //最后调用Person的展示接口printf("\n第二种装扮:");Suit xz;Tie ld;LeatherShoes px;xz.Show();ld.Show();px.Show();xc.Show(); printf("\n");  return 0;
}

代码运行效果如下:

版本二中,Rerson类和服饰类是完全独立的,搭配衣服的过程也只是一个一个将对应词打印出来。下面来看版本三。

2.3 版本三

版本三用到了本篇要讲的装饰器模式。

在本例中,服饰就是装饰类,具体的服饰,T恤、球鞋这些是具体的装饰类,而人就是要被装饰的组件,那是组件Component还是具体组件ConcreateComponet呢?

本例中,只有一个ConcreateComponet具体组件类,就没必要单独建立一个Component组件类,可以把两者职责合并成一个类,也就是只使用ConcreateComponet类表示Person类。

2.3.1 Person类与服饰类

Person类与服饰类的代码如下:

// Person类
class Person
{
public:Person(){};Person(std::string name){m_name = name;}// 父类的函数virtual void Show(){printf("装扮的%s", m_name.c_str());}    private:std::string m_name;
};// 服饰类(Decorator)
class Finery : public Person
{
protected:Person *m_pComponent = nullptr;public:void Decorate(Person *pComponent){m_pComponent = pComponent;}// 子类的函数void Show(){if (m_pComponent != nullptr){m_pComponent->Show();}}
};// 具体服饰类(ConcreateDecorator)
class TShirts : public Finery
{
public:void Show(){printf("大T恤 ");Finery::Show();}   
};class BigTrouser : public Finery
{
public:void Show(){printf("垮裤 ");Finery::Show();}    
};class Sneakrs : public Finery
{
public:void Show(){printf("破球鞋 ");Finery::Show();}    
};class Suit : public Finery
{
public:void Show(){printf("西装 ");Finery::Show();}    
};class Tie : public Finery
{
public:void Show(){printf("领带 ");Finery::Show();}    
};class LeatherShoes : public Finery
{
public:void Show(){printf("皮鞋 ");Finery::Show();}    
};

2.3.2 主函数

主函数的逻辑如下,先实例化一个名为"小菜"的Person对象,

然后再依次实例化要装扮的服饰类对象,接着通过“包装”的方式,后一个对象对前一个对象进行包装,

最后调用最终包装后对象的展示接口:

int main()
{Person *xc = new Person("小菜");printf("\n第一种装扮:");TShirts    *dtx = new TShirts();BigTrouser *kk  = new BigTrouser(); Sneakrs    *pqx = new Sneakrs();dtx->Decorate(xc); // 装饰过程:先用大裤衩装饰小菜kk->Decorate(dtx); // 再用垮裤装饰穿了大裤衩的小菜pqx->Decorate(kk); // 再用破球鞋装饰穿了大裤衩和垮裤的小菜pqx->Show();       // 最后调用最外层的装饰对象的展示接口printf("\n第二种装扮:");Suit         *xz = new Suit();Tie          *ld = new Tie();LeatherShoes *px = new LeatherShoes();xz->Decorate(xc); // 装饰过程:先用西装装饰小菜ld->Decorate(xz); // 再用领带装饰穿了西装的小菜px->Decorate(ld); // 再皮鞋装饰穿了西装和领带的小菜px->Show();       // 最后调用最外层的装饰对象的展示接口  printf("\n");  return 0;
}

代码运行效果如下:

装饰模式的优缺点与适用场景:

3 总结

本篇介绍了设计模式中的装饰模式,并通过给人装扮的实例,使用C++编程,来演示装饰模式的使用。

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

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

相关文章

嵌入式linux系统中SPI子系统原理分析01

大家好,今天给大家分享一下,如何使用linux系统中的SPI通信协议,实现主从设备之间的信息传递。 SPI是一种常见的设备通用通信协议。它是一个独特优势就是可以无中断发送数据,可以连续发送或接收任意数量的位。而在I2C和UART中,数据以数据包的形式发送,有限定位数。 …

FreeBSD通过CBSD管理低资源容器jail来安装Ubuntu子系统实践

简介 FreeBSD、CBSD、Jail和Ubuntu&#xff0c;四者的组合方案可以说是强强联合&#xff0c;极具性价比和竞争力&#xff01;同时安装简单方便&#xff0c;整体方案非常先进。 CBSD是为FreeBSD jail子系统、bhyve、QEMU/NVMM和Xen编写的管理层。该项目定位为一个综合解决方案…

wondershaper 一款限制 linux 服务器网卡级别的带宽工具

文章目录 一、关于奇迹整形器二、文档链接三、源码下载四、限流测试五、常见报错1. /usr/local/sbin/wondershaper: line 145: tc: command not found2. Failed to download metadata for repo ‘appstream‘: Cannot prepare internal mirrorlist: No URLs.. 一、关于奇迹整形…

Langchain中使用Ollama提供的Qwen大模型进行Function Call实现天气查询、网络搜索

Function Call&#xff0c;或者叫函数调用、工具调用&#xff0c;是大语言模型中比较重要的一项能力&#xff0c;对于扩展大语言模型的能力&#xff0c;或者构建AI Agent&#xff0c;至关重要。 Function Call的简单原理如下&#xff1a; 按照特定规范&#xff08;这个一般是L…

多尺度特征提取:原理、应用与挑战

多尺度 多尺度特征提取&#xff1a;原理、应用与挑战**原理****应用****挑战****总结** 多尺度特征提取&#xff1a;原理、应用与挑战 在计算机视觉、自然语言处理和信号处理等领域&#xff0c;有效地捕捉和解析数据的多种尺度特性是至关重要的。多尺度特征提取是一种技术&…

融资融券有哪些交易技巧,两融利率现在最低多少?4.0%!

融资融券交易技巧 授信额度技巧 当我们账户净资产有显著增长时&#xff0c;最好主动申请增加信用额度&#xff0c;这样在后面行情好转入资金需要进行更多融资融券交易时就不会受限于授信额度&#xff0c;避免因为临时申请增加额度而错过交易机会。 买入委托技巧 现金的折算率…

小孟再接盲盒小程序,3天开发完!

大家好&#xff0c;我是程序员小孟。 前面开发了很多的商业的单子&#xff0c;私活联盟的小伙伴慢慢的逐渐搞自己的产品。 前面的话&#xff0c;开发了盲盒小程序&#xff0c;最近又接了一款盲盒小程序。因为前面有开发过&#xff0c;所以我们的成本也少了很多。 盲盒小程序…

2024.6.17 作业 xyt

今日作业&#xff1a; 升级优化自己应用程序的登录界面。 要求&#xff1a; 1. qss实现 2. 需要有图层的叠加 &#xff08;QFrame&#xff09; 3. 设置纯净窗口后&#xff0c;有关闭等窗口功能。 4. 如果账号密码正确…

Marin说PCB之orcad-capture原理图封装库的创建总结----01

今天是个不错的日子&#xff0c;我早上一出门刚骑车到半路就开始下大雨了&#xff0c;可是天气预报上明明说的没有雨啊&#xff0c;所以说天气预报就像是女人的脾气一样&#xff0c;难以揣摩啊&#xff0c;也尽量少去揣摩吧。 小编我刚刚到公司&#xff0c;就收到美国分部同事J…

【C语言】排序算法 -------- 计数排序

个人主页 创作不易&#xff0c;感谢大家的关注&#xff01; 文章目录 1. 计数排序的概念2. 计数排序使用场景3. 计数排序思想4. 计数排序实现过程5. 计数排序的效率6. 总结&#xff08;附源代码&#xff09; 1. 计数排序的概念 计数排序是一种非比较的排序算法&#xff0c;其…

分享三款AI智能修图工具,超实用!

随着AI技术的飞速发展&#xff0c;图像处理领域正经历着一场颠覆性的革新。如今&#xff0c;众多繁琐的图像处理任务&#xff0c;诸如修图、抠图以及高清修复等&#xff0c;均可以借助先进的AI技术实现自动化处理。相较于传统的人工操作&#xff0c;AI图像工具不仅极大地提升了…

3d中毒了打不开模型怎么办---模大狮模型网

3D中毒了打不开模型怎么办&#xff1f;这是很多3D爱好者都会遇到的问题。在使用3D建模软件时&#xff0c;有时会出现打不开模型的情况&#xff0c;这可能是由于软件本身的问题&#xff0c;也可能是由于电脑配置不够高导致的。下面我们就来看看如何解决这个问题。 首先&#xff…

探索未来通信的新边界:AQChat一款融合AI的在线匿名聊天

探索未来通信的新边界&#xff1a;AQChat一款融合AI的在线匿名聊天 在数字时代&#xff0c;即时通讯变得无处不在&#xff0c;但隐私和性能仍旧是许多用户和开发者关注的焦点。今天&#xff0c;我要介绍一个开创性的开源项目 —— AQChat&#xff0c;它不仅重定义了在线匿名聊…

Ollama+Open WebUI本地部署Llama3 8b(附踩坑细节)

先展示一下最终结果&#xff0c;如下图所示&#xff1a; 1. 添加环境变量 在下载 ollama 之前&#xff0c;先去配置环境变量&#xff0c;确保模型下载到我们想要的地方 win10 和 win11 输入path或者环境变量&#xff1a; 增加系统环境变量 变量名不可更改&#xff0c;必须是O…

[ARM-2D 专题]3. ##运算符

C语言的宏系统相当强大&#xff0c;它允许使用##符号来处理预处理期的文本替换。这种用法被称为标记连接&#xff08;token pasting&#xff09;操作&#xff0c;其结果是将两个标记紧紧地连接在一起&#xff0c;而省略掉它们之间的所有空格。在复杂的宏定义中&#xff0c;运用…

Debian/Ubuntu linux安装软件

1、官方软件商店安装 2、deb包安装 报错不是sudoers&#xff0c;首先将用户添加到sudo su -l adduser USERNAME sudo exit然后&#xff0c;退出桌面环境并再次登录。 您可以通过输入以下内容来检查上述过程是否成功&#xff1a; groups下载deb包 altshiftf4或右键打开命令行…

10.无代码爬虫软件做网页数据抓取流程——工作流程设置与数据预览

首先&#xff0c;多数情况下免费版本的功能&#xff0c;已经可以满足绝大多数采集需求&#xff0c;想了解八爪鱼采集器版本区别的详情&#xff0c;请访问这篇帖子&#xff1a;https://blog.csdn.net/cctv1123/article/details/139581468 八爪鱼采集器免费版和个人版、团队版下…

安卓实现输入快递单号生成二维码,摄像头扫描快递单号生成的二维码,可以得到快递信息

背景&#xff1a; 1、实现二维码的生成和识别2、实现andriod&#xff08;或虚拟机&#xff09;部署&#xff0c;调用摄像头3、实现网络管理&#xff0c;包括数据库【取消】2、3可以组队实现&#xff0c;1必须单人实现 过程&#xff1a; 安卓APP主界面 输入快递单号信息&#…

关于伪标头那些事

前言 看到伪标头&#xff0c;不少同学可能会比较陌生&#xff0c;因为谁让它默默无闻呢&#xff1f; 当然博主把它比喻为一个来自传输层的“共享盒子”。提到共享&#xff0c;我想大家有所体会了。这里给大家贴一张直观的图例&#xff0c;可以静静观摩之。 Q&#xff1a;什么是…

MFC扩展库BCGControlBar Pro v35.0新版亮点:重新设计的工具栏编辑器等

BCGControlBar库拥有500多个经过全面设计、测试和充分记录的MFC扩展类。 我们的组件可以轻松地集成到您的应用程序中&#xff0c;并为您节省数百个开发和调试时间。 BCGControlBar专业版 v35.0已全新发布了&#xff0c;这个版本改进类Visual Studio 2022的视觉主题、增强对多个…