一. 举例

我之前做过一个文件系统就叫 MyFileSys 吧,后来的话,客户想加入一些附加功能,比如压缩、加密、杀毒之类的操作,这些附加操作没有先后顺序,比如你可以先压缩再加密,也可以先杀毒再压缩,等等。

这些附加功能是可选的,有的客户要这些功能,有的不要,有的要其中的几种附加功能等等。怎么设计呢?

第一种方案:
直接修改这个独立的文件系统 MyFileSys,对于不同的客户实现不同的文件系统。

后来随着客户的增多,发现维护和修改的工作量越来越大。因为每增加一个客户就要重新生成一个类,然后把客户想要的附加功能加入,更加郁闷的是,只针对一个客户有时也是要修改很多次,客户今天要这些附加功能,明天又想加入另外一些功能,这样改来改去,维护工作量也是很大的。

第二种方案:

后来改用第二种方案,实现一个单独的附加功能类,保持原文件系统不变,这样在客户端就可以轻松的加入一些附加功能。

代码如下:

  1. //定义一个对象接口,可以给这些对象动态地添加职责
  2. class FileSys
  3. {
  4. public:
  5. virtual ~FileSys()
  6. {
  7. }
  8. virtual void Operation()
  9. {
  10. }
  11. protected:
  12. FileSys()
  13. {
  14. }
  15. };
  16. //定义一个具体的对象
  17. class MyFileSys:public FileSys
  18. {
  19. public:
  20. MyFileSys()
  21. {
  22. }
  23. ~MyFileSys()
  24. {
  25. }
  26. void Operation()
  27. {
  28. cout<<"MyFileSys operation..."<<endl;
  29. }
  30. };
  31. //装饰抽象类
  32. class Decorator:public FileSys
  33. {
  34. public:
  35. Decorator(FileSys* fileSys)
  36. {
  37. this->_fileSys = fileSys;
  38. }
  39. virtual ~Decorator()
  40. {
  41. delete _fileSys;
  42. }
  43. void Operation()
  44. {
  45. }
  46. protected:
  47. FileSys* _fileSys;
  48. };
  49. //压缩装饰类
  50. class ZipDecorator:public Decorator
  51. {
  52. public:
  53. ZipDecorator(FileSys* fileSys):Decorator(fileSys)
  54. {
  55. }
  56. ~ZipDecorator()
  57. {
  58. }
  59. void Operation()
  60. {
  61. _fileSys->Operation(); //首先运行以前的功能
  62. this->AddedZipBehavior(); //附加功能
  63. }
  64. void AddedZipBehavior()
  65. {
  66. cout<<"Added Zip Behavior...."<<endl;
  67. }
  68. };
  69. //杀毒装饰类
  70. class KillVirDecorator:public Decorator
  71. {
  72. public:
  73. KillVirDecorator(FileSys* fileSys):Decorator(fileSys)
  74. {
  75. }
  76. ~KillVirDecorator()
  77. {
  78. }
  79. void Operation()
  80. {
  81. _fileSys->Operation();
  82. this->AddedKillVirBehavior();
  83. }
  84. void AddedKillVirBehavior()
  85. {
  86. cout<<"Added Kill Virus Behavior...."<<endl;
  87. }
  88. };
  89. //加密装饰类
  90. class EncryptDecorator:public Decorator
  91. {
  92. public:
  93. EncryptDecorator(FileSys* fileSys):Decorator(fileSys)
  94. {
  95. }
  96. ~EncryptDecorator()
  97. {
  98. }
  99. void Operation()
  100. {
  101. _fileSys->Operation();
  102. this->AddedEncrypeBehavior();
  103. }
  104. void AddedEncrypeBehavior()
  105. {
  106. cout<<"Added Encrypt Behavior...."<<endl;
  107. }
  108. };
  109. //////////////////////////////////////////////////////////////////////////
  110. //测试
  111. int main()
  112. {
  113. FileSys* fileSys = new MyFileSys();
  114. Decorator* dec1 = new ZipDecorator(fileSys);  //在原文件系统上,加入压缩功能
  115. Decorator* dec2 = new KillVirDecorator(dec1); //在之前的基础上,加入杀毒功能
  116. Decorator* dec3 = new EncryptDecorator(dec2); //再加入加密功能
  117. dec3->Operation();
  118. return 0;
  119. }

这样之后,如果要添加附加功能,实现起来就很方便了。这种模式就是装饰模式。

二. 装饰模式

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

说明:

Componet,主要是定义一个接口,通过这个接口可以给这些对象(ConcreteComponent)添加职责。

Dectorator,装饰类,通过外类(ConcreteDecorator)来扩展Component 类的功能,对于Component来说,是无需知道这个抽象类的存在的。

ConcreteDecorator,具体装饰类,添加具体的附加功能。

优点:

1. 装饰类是为已有功能动态地添加更多功能的一种方式。

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

三. 问题讨论

从上图可以看到 Decorator 是继承于 Component
的,也就和 ConcreteComponent 成了兄弟了,但是 Decorator 的作用却是修饰 ConcreteComponent
的,这点好像是很怪怪的!!最说不通的是Decorator 与 Component 是没有is-a关系的!!

我个人觉得:

1. 这个继承关系,不应该是我们要重点关注的。这里使用继承主要是为了要重用 Operation() 这个接口,以达修饰的目的。

2. 重点是 Decorator 与 Component 这个组合关系。装饰类里有一个Component 指针,正是由于它的存在才能修饰到具体的 Component 对象。

设计模式C++描述----10.装饰(Decorator)模式的更多相关文章

  1. 《Head First 设计模式》ch.3 装饰(Decorator)模式

    设计原则 类应该对修改关闭,对扩展开放(开放-关闭原则).在每个地方使用开放-关闭原则是一种浪费,也没有必要,因为这通常会引入新的抽象层次,增加代码复杂度.需要把注意力集中在设计中最有可能改变的地方. ...

  2. 设计模式(八)装饰器模式Decorator(结构型)

    设计模式(八)装饰器模式Decorator(结构型) 1. 概述 若你从事过面向对象开发,实现给一个类或对象增加行为,使用继承机制,这是所有面向对象语言的一个基本特性.如果已经存在的一个类缺少某些方法 ...

  3. php设计模式课程---7、装饰器模式如何使用

    php设计模式课程---7.装饰器模式如何使用 一.总结 一句话总结: 装饰器的核心是获取了文章类整个类,而不是获取了文章内容,有了这个文章类,我想给你加多少装饰就给你加多少装饰(将文章这个类封装进去 ...

  4. 设计模式(九)——装饰者模式(io源码分析)

    1 星巴克咖啡订单项目(咖啡馆): 1) 咖啡种类/单品咖啡:Espresso(意大利浓咖啡).ShortBlack.LongBlack(美式咖啡).Decaf(无因咖啡) 2) 调料:Milk.So ...

  5. 大型Java进阶专题(八)设计模式之适配器模式、装饰者模式和观察者模式

    前言 ​ 今天开始我们专题的第八课了.本章节将介绍:三个设计模式,适配器模式.装饰者模式和观察者模式.通过学习适配器模式,可以优雅的解决代码功能的兼容问题.另外有重构需求的人群一定需要掌握装饰者模式. ...

  6. 装饰(Decorator)模式

    1.装饰(Decorator)模式    动态给一个对象添加一些额外的职责.就增加功能来说,装饰模式比生成子类更为灵活.Component是定义一个对象接口.可以给这些对象动态地添加职责.Concre ...

  7. 设计模式之第10章-桥接模式(Java实现)

    设计模式之第10章-桥接模式(Java实现) “一入软件深似海,从此早睡是路人.黑夜给了我黑色的眼睛,我却用他去寻找八阿哥.”“怎么了,又来那么多的感慨啊.”“还能有什么啊,老板是说让换个APP做,这 ...

  8. ④ 设计模式的艺术-10.装饰(Decorator)模式

    职责 装饰模式是在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能.它是通过创建一个包装对象,也就是装饰来包裹真实的对象. 装饰模式是一种用于代替继承的技术,无需通过继承增加子类就能扩展对 ...

  9. 【设计模式 - 9】之装饰者模式(Decorator)

    1      模式简介 装饰者模式允许向一个现有的对象添加新的功能,同时又不改变其结构. 装饰者模式的思路是用"调料"对象将原始对象进行层层包裹,同时其属性.动作层层传递,达到最终 ...

随机推荐

  1. [Next] 初见next.js

    next 简介 Next.js 是一个轻量级的 React 服务端渲染应用框架 next 特点 默认情况下由服务器呈现 自动代码拆分可加快页面加载速度 简单的客户端路由(基于页面) 基于 Webpac ...

  2. Circular RNA的产生机制、功能及RNA-seq数据鉴定方法

    推荐关注微信公众号:AIPuFuBio,和使用免费生物信息学资源和工具AIPuFu:http://www.aipufu.com. [Circular RNA的产生机制] Circular RNA,缩写 ...

  3. .net core 3.0 Signalr - 01 基础篇

    因为将signalr作为单独的站点,此处需要建立两个项目,一个专门用于signalr作为推送项目,一个客户端(实际的业务项目) ## 基础知识速览 ### Clients对象属性 | 属性 | 描述 ...

  4. Mac 安装node npm cnpm vue 以及卸载 node 和 npm 的方法 清空npm缓存的方法

    S01 安装node(内含npm) 首先,到官网下载长期支持版,截止目前,最新的长期支持版本号是10.16.3 https://nodejs.org/zh-cn/download/ 下载完毕后,安装该 ...

  5. Flask上下文管理机制流程(源码剖析)

    Flask请求上下文管理 1 偏函数 partial 使用该方式可以生成一个新函数 from functools import partial def mod( n, m ): return n % ...

  6. pinpoint1.8.5安装及使用指南

    简介 pinpoint是开源在github上的一款APM监控工具,它是用Java编写的,用于大规模分布式系统监控.它对性能的影响最小(只增加约3%资源利用率),安装agent是无侵入式的. 各大APM ...

  7. .Net Core下使用HtmlAgilityPack解析采集互联网数据

    HtmlAgilityPack应该算是.Net下最好用的html解析库了. 因为最近帮朋友采集一些数据,在nuget里面搜索了好几个库,最后决定就用HtmlAgilityPack.并简单的记录下使用的 ...

  8. 为什么一个Http Header中的空格会被骇客利用 - HTTP request smuggling

    figure:last-child { margin-bottom: 0.5rem; } #write ol, #write ul { position: relative; } img { max- ...

  9. session,cookie,sessionStorage,localStorage的相关设置以及获取删除

    一.cookie 什么是 Cookie? "cookie 是存储于访问者的计算机中的变量.每当同一台计算机通过浏览器请求某个页面时,就会发送这个 cookie.你可以使用 JavaScrip ...

  10. Linux上安装jdk1.8和配置环境变量

    前言 Linux 上安装jdk1.8 和配置环境变量,参考相关文档,本人在此总结,操作归纳如下. 第一步:创建jdk安装目录(该/usr/local/src 目录是空的,最好把我们自己下载的放到这,容 ...