文章目录

  • 装饰器模式使用场景
    • 引入装饰器模式
    • 另一个装饰器模式的例子---计算水果饮料的价格
  • 装饰器模式的定义

装饰器模式使用场景

我们的游戏中一般都会有UI(用户接口)界面,比如背包中的格子:

或者一些文本UI:

比如现在想要绘制这样一个界面,先后为一个普通的列表控件增加边框、垂直滚动条、水平滚动条:

我们可以采用继承的设计思路:

  1. 创建一个ListCtrl类,代表普通列表,提供draw方法。
  2. BorderListCtrl类,继承ListCtrl,增加边框,提供draw方法。
  3. VerScBorderListCtrl类继承 BorderListCtrl类,增加边框的垂直滚动条,提供draw方法。
  4. HorScVerScBorderListCtrl类,继承VerScBorderListCtrl,增加了边框、垂直、水平滚动条,提供draw方法。

但是后续如果我们想要增加其他效果,就又需要继承新的子类。

我们修改一下设计思路,将继承的方式改为组装的方式来解决,从而防止类泛滥:

  1. ListCtrl类代表普通列表,提供draw方法。
  2. 如果给ListCtrl增加一个边框的组件,就形成了带边框的列表。

上面这种通过装饰方式,将一个类的功能不断增强的思想(动态地增加新功能),就是装饰器模式的思想。

引入装饰器模式

根据“组合复用原则”,如果两个类使用继承进行设计,则父类代码的修改可能影响子类的行为,而且可能父类中的很多方法子类是用不上的,这显然是一种浪费,如果使用组合进行设计,则可以大大降低两个类之间的依赖关系,也不会存在因继承关系导致的浪费行为。
所以如果继承和组合都能够达到设计目的,则优先考虑使用组合。

我们将不同的装饰器类分别实现,并且他们都继承自抽象的装饰器类,并且可以调用传入的抽象类指针来执行传入的装饰器功能。

#include <iostream>
using namespace std;namespace hjl_project1
{//抽象的列表类class Control{public://将自身绘制到屏幕上virtual void draw() = 0;virtual ~Control() {}};//列表本体class ListCtrl : public Control{public:virtual void draw(){//具体的绘制工作可以用openGL等工具,具体代码省略cout << "绘制了普通的列表" << endl;}};//抽象的装饰器类class Decorator : public Control{public:Decorator(Control *tmpctrl): m_control(tmpctrl){}virtual void draw(){m_control->draw();}private://需要被装饰的列表Control *m_control;};//-----------------------------------------//具体的边框装饰器类class BorderDec : public Decorator{public:BorderDec(Control *tmpctrl): Decorator(tmpctrl){}virtual void draw(){//调用父类的draw,绘制列表Decorator::draw();drawBorder();}private:void drawBorder(){cout << "绘制边框" << endl;}};//具体的垂直滚动条装饰器类class VerScrollBarDec : public Decorator{public:VerScrollBarDec(Control *tmpctrl): Decorator(tmpctrl){}virtual void draw(){//调用父类的draw,绘制列表Decorator::draw();drawCerScrollBar();}private:void drawCerScrollBar(){cout << "绘制垂直滚动条" << endl;}};//具体的水平滚动条class HorScrollBarDec : public Decorator{public:HorScrollBarDec(Control *tmpctrl): Decorator(tmpctrl){}virtual void draw(){//调用父类的draw,绘制列表Decorator::draw();drawHorScrollBar();}private:void drawHorScrollBar(){cout << "绘制水平滚动条" << endl;}};
}
int main()
{using namespace hjl_project1;//创建一个又带边框,又带垂直滚动条的列表// 1.先创建一个列表本体Control *plistctrl = new ListCtrl();// 2.借助本体和装饰器,实现又带边框又带垂直滚动条Decorator *plistctrl_b = new BorderDec(plistctrl);Decorator *plistctrl_b_v = new VerScrollBarDec(plistctrl_b);plistctrl_b_v->draw();
}


可以看到上面的Decorator和Control两个类既是继承关系又是组合关系。

另一个装饰器模式的例子—计算水果饮料的价格

一杯单纯的水果饮料售价10元;如果向饮料中增加砂糖,则额外要多加1元;如果加牛奶,额外多加2元;增加珍珠,多加2元。
如果顾客又加珍珠又加砂糖,则需要13元。

使用装饰器模式来实现这个情景,就比较合适。

#include <iostream>
using namespace std;namespace hjl_project2
{//抽象饮料类class Beverage{public:virtual int getprice() = 0;virtual ~Beverage() {}};//水果饮料类class FruitBeverage : public Beverage{public:int getprice(){return 10;}};//抽象的装饰器类class Decorator : public Beverage{public:Decorator(Beverage *tmpbvg): m_pbvg(tmpbvg){}virtual int getprice(){return m_pbvg->getprice();}private:Beverage *m_pbvg;};//具体的“砂糖”装饰器类class SugarDec : public Decorator{public:SugarDec(Beverage *tmpbvg): Decorator(tmpbvg){}virtual int getprice(){return Decorator::getprice() + 1;}};//具体的“牛奶”装饰器类class MilkDec : public Decorator{public:MilkDec(Beverage *tmpbvg): Decorator(tmpbvg){}virtual int getprice(){return Decorator::getprice() + 2;}};//具体的“珍珠”装饰器类class BubbleDec : public Decorator{public:BubbleDec(Beverage *tmpbvg): Decorator(tmpbvg){}virtual int getprice(){return Decorator::getprice() + 2;}};
}
int main()
{using namespace hjl_project2;Beverage *pfruit = new FruitBeverage();//增加珍珠Decorator *pfruit_addbubble = new BubbleDec(pfruit);//增加砂糖Decorator *pfruit_addbubble_addsugar = new SugarDec(pfruit_addbubble);cout << "增加了珍珠和砂糖的水果饮料的价格为:" << pfruit_addbubble_addsugar->getprice() << endl;
}

如果后续想增加新的饮料类型,比如增加“茶饮料”为20元,则只需要继承抽象类即可:


装饰器模式的定义

动态地给一个对象添加一些额外的职责,就增加功能来说,该模式相比生成子类更加灵活(减少了子类泛滥)。符合“开闭原则”。

装饰器模式一般包含四个角色:

  1. Control(抽象构件):抽象接口draw,让调用者以一致的方式来处理未被修饰的对象以及经过修饰后的对象,实现客户端的透明操作。
  2. ListCtrl(具体构建):实现抽象构件定义的接口,此后装饰器就可以给该构建增加额外的方法(职责)。
  3. Decorator(抽象装饰器类):定义着一个与抽象接口draw相同的接口,后续通过对该接口的扩展,达到增加功能的目的。
  4. BorderDec、VerScrollBarDec、HorScrollBarDec(具体装饰器类):增加了具体的装饰方法,通过对draw接口的扩展,来起到增加功能的目的。

装饰器对象和被装饰对象有相同的父类(Control),这样做的好处是装饰器对象就能够取代被装饰的对象,并可以用一个或多个装饰器包装一个对象。

但是这个模式有一个不足之处,那就是会产生许多中间的小对象,占用了资源并且不容易管理。

C++设计模式----装饰器模式相关推荐

  1. Python设计模式-装饰器模式

    Python设计模式-装饰器模式 代码基于3.5.2,代码如下; #coding:utf-8 #装饰器模式class Beverage():name = ""price = 0.0 ...

  2. Go 设计模式 - 装饰器模式

    装饰模式使用对象组合的方式动态改变或增加对象行为.Go语言借助于匿名组合和非入侵式接口可以很方便实现装饰模式.使用匿名组合,在装饰器中不必显式定义转调原对象方法. 设计模式 装饰器模式 装饰器模式主要 ...

  3. Spring设计模式(装饰器模式)

    Spring设计模式(装饰器模式) 模式的定义: 装饰者模式定义: ​ 动态地为一个对象添加一些额外的职责,若要扩展一个对象的功能,装饰者提供了比继承更有弹性的替代方案. 模式的结构图 : 模式包含角 ...

  4. Java设计模式-装饰器模式 理论代码相结合

    继Java设计模式适配器模式后的装饰器模式来啦,让我们一起看看吧. 会了就当复习丫,不会来一起来看看吧. 很喜欢一句话:"八小时内谋生活,八小时外谋发展". 如果你也喜欢,让我们一 ...

  5. 设计模式--装饰器模式

    装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装.简单来说,装饰器模式就是 ...

  6. PHP设计模式——装饰器模式

    声明:本系列博客参考资料<大话设计模式>,作者程杰. 装饰器模式又叫装饰者模式.装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能.它是通过创建一个包装对象,也就是装 ...

  7. 设计模式-装饰器模式 C++

    一.简介 1.什么是装饰器模式 装饰器模式是结构型设计模式. 装饰器是现有类的一个包装,可以在不修改现有类且不增加子类的情况下扩展现有类. [注]可以实现向一个现有对象添加新的功能,同时又不改变其结构 ...

  8. 设计模式---装饰器模式(C++实现)

    装饰器模式(Decorator Pattern)允许向一个现有对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰类,用来包装原 ...

  9. C++设计模式 装饰器模式

    文章目录 1. 先验知识 2. 装饰器模式相关概念 3. 装饰器模式的应用 3.1 应用1: 给形状添加新的特征 不同形状加红 3.2 应用2: 给一个人穿不同的衣服 a 直接person类, 增加穿 ...

  10. 白话设计模式-装饰器模式的使用和意义

    装饰器模式展示 在学习设计模式的过程中,将自己对于设计模式的理解,以最简单,最白话的方式,分享给大家.个人觉得,对于设计模式的理解,需要将他从最抽象的理论里,真实的代入到实际的业务场景中,将会有最深刻 ...

最新文章

  1. PHP设置禁止目录索引,/var/www/html目录索引禁止
  2. Django--models一对多实例
  3. vba 跳出for循环_VBA简单入门08:For循环
  4. hibernate数据的三种存在状态(只与事务有关)
  5. anaconda的执行路径
  6. python基础-C扩展
  7. 移动端真机调试,手机端调试,移动端调试
  8. JQM页面跳转,多种效果
  9. 汇编学习 step by step
  10. 线性回归模型异方差解决方法
  11. piblic class 和class的区别
  12. 【unity 3d】--- 瞄准镜效果
  13. 宝可梦合体再次流行?Pokemon Fusion的技术实现
  14. 颠覆物理学的中微子:宇宙中飞行速度几乎达到光速
  15. 北京将评估分时分区单双号限行 推进错时上下班 (zz)
  16. 【实例分割|Mask2Former】 解决模型推理预测的代码中存在的一些问题
  17. 音频编辑专家下载v9.3.0.4官方免费版
  18. 华为服务器网口显示down,[已解决]华为三层交换机新建vlan后端口总是down的状态[已解决]~有好心人帮忙看看吗?谢谢~ - 华为技术论坛 - 51CTO技术论坛_中国领先的IT技术社区...
  19. 谷歌员工分享的关于李开复先生的小故事
  20. 项目实训-----unity多人游戏开发----第三篇

热门文章

  1. 一段php代码,请问一段PHP代码是什么意思?
  2. 17.AD域和LDAP协议
  3. 《R语言与统计分析》-探索性数据分析
  4. MySQL笔记(基础)
  5. python爬虫之b站视频下载(python学习笔记)
  6. 有了这个机器学习画图神器,论文、博客都可以事半功倍了!
  7. 学计算机swot分析怎么写,计算机专业学生个人SWOT分析示例
  8. 图像拼接缝融合之加权融合
  9. 手机 平板 屏幕分辨率 尺寸 长宽比
  10. 网络上摘抄的数据库设计规范