女人常说男人喜新厌旧,只见新人笑,那闻旧人哭,但装饰模式(Decorator)却是一种结交新朋友不忘老朋友的设计模式,非常适合去古代当老公(现代是不行的,因为只能娶一个老婆了)。装饰模式的本质是每一个装饰对象都被保留一个被其装饰的对象,装饰对象在展示新功能时会同时去调用被其装饰的对象的同功能函数,通过如此层层包含调用(即装饰),形成一个类似链表的结构,接下来的介绍中,我们还会看到更多的类似链表结构的设计模式,比如职责链模式、状态模式。
       仍以《大话设计模式》一书中装饰模式的小菜穿衣的例子为例,来看看装饰模式是如何做到家里红旗不倒,外面彩旗飘飘的。小菜要去会妹子,临行前为了给妹子留个好印象,精选牛仔裤一条,然后搭上简约风T恤,装扮一新后出门,为了能够让小菜搭配任何衣服,使用装饰模式描述这一过程。
1、穿衣基类,只有一个函数Show(),显示穿的衣服

  1. class CDress
  2. {
  3. public:
  4. virtual ~CDress() {}
  5.  
  6. virtual void Show()
  7. {
  8. printf("dressed boy.\n");
  9. }
  10. };

2、装饰类基类

  1. class CFinery : public CDress
  2. {
  3. public:
  4. CFinery() : m_poDress(NULL) {}
  5. virtual ~CFinery() {}
  6.  
  7. virtual void Show()
  8. {
  9. if (m_poDress)
  10. {
  11. m_poDress->Show();
  12. }
  13. }
  14.  
  15. void Decorate(CDress* poCDress)
  16. {
  17. m_poDress = poCDress;
  18. }
  19.  
  20. private:
  21. CDress* m_poDress;
  22. };

3、T恤和牛仔裤的具体装饰类

  1. class CTShirt : public CFinery
  2. {
  3. public:
  4. virtual ~CTShirt() {}
  5.  
  6. void Show()
  7. {
  8. printf("Tshirt ");
  9. CFinery::Show();
  10. }
  11. };
  12.  
  13. class CJeans : public CFinery
  14. {
  15. public:
  16. virtual ~CJeans() {}
  17.  
  18. void Show()
  19. {
  20. printf("Jeans ");
  21. CFinery::Show();
  22. }
  23. };

这里需注意,装饰类对象的Show()函数在显示出本对象的装扮的同时,需要去调用装饰基类的Show()函数,以显示其被装饰对象的旧有装扮,即不能忘了老朋友。

4、装饰过程

  1. int main(int argc, char* argv[])
  2. {
  3. CDress oCDress;
  4. CTShirt oCTShirt;
  5. CJeans oCJeans;
  6.  
  7. oCTShirt.Decorate(&oCDress);
  8. oCJeans.Decorate(&oCTShirt);
  9. oCJeans.Show();
  10.  
  11. return 0;
  12. }

通过装饰过程可以看出,oCJeans 对象装饰了 oCTShirt 对象,所以 oCJeans 调用 Show() 函数时会调用 oCTShirt 的 Show() 函数,oCTShirt 又装饰了 oCDress 对象,这时 oCTShirt 又会调用 oCDress 的 Show() 函数,有点类似递归,也有点类似链表的味道,当然我们知道递归需要有一个终结者的,不然就没完没了了,所以最后被装饰的对象 oCDress 是不在有任何装饰对象的。

同时,如果小菜的妹子不喜欢这套打扮风格了,说要小菜把T恤换成衬衫,这时我们只要新增一个衬衫装饰类 CShirt ,然后把 oCJeans 的装饰对象换成 CShirt 即可,这里可见,使用了装饰模式后,换衣服都方便灵活多了。

5、装饰模式的应用
         装饰模式适合在原有功能上增加了新功能,但是新功能被调用前/后仍需要调用原有功能的情况,特别适合功能一层一层的扩展,同时保持旧有功能的正常调用的场景。比如我们设计一个编辑框的控件类,最初只有编辑文字的功能,我们新增一个装饰类后,我们能编辑出彩色的文字,这时我们只需要设置控件的背景颜色,然后去调用旧的对象编辑文字功能即可。过一段时间老大提新要求了,要求这个编辑框控件要搞和谐社会,要屏蔽敏感词,这时我们再新增一个装饰类,增加建设和谐社会功能后,再去调用编辑彩色文字的装饰类。当然,我们还能灵活变动,搞和谐社会的装饰类为了不花哨,也可以直接装饰原来的编辑框控件类,抛弃中间搞彩色文字的过程。

大话设计模式C++版——装饰模式的更多相关文章

  1. 大话设计模式C++版——代理模式

    本篇开始前先发个福利,程杰的<大话设计模式>一书高清电子版(带目录)已上传至CSDN,免积分下载. 下载地址:http://download.csdn.net/detail/gufeng9 ...

  2. 大话设计模式C++版——工厂模式在COM中的典型应用

    上篇<大话设计模式C++版——抽象工厂模式>中,我们拯救世界未遂,留下小小的遗憾,本篇中我们将给出一个解决方案——COM组件技术,同时也顺便扯扯工厂模式在COM组件技术中的应用. 工厂模式 ...

  3. 大话设计模式C++版——抽象工厂模式

    前面说过,简单工厂模式是最基础的一种设计模式,那以工厂命名的设计模式就是23种设计模式中最多的一种,他们一脉相承,一步一步进化而来,这里就是其中的最后一种——抽象工厂模式(Abstract Facto ...

  4. 大话设计模式C++版——工厂方法模式

    工厂方法模式是以简单工厂模式为基础的,如果未了解简单工厂模式的同学可先浏览<大话设计模式C++版——简单工厂模式>.在简单工厂模式中,提到过简单工厂模式的缺陷,即违背了开发—封闭原则,其主 ...

  5. 大话设计模式C++版——表驱动法改造简单工厂

    上回<大话设计模式C++版——简单工厂模式>中指出了简单工厂模式的缺陷,即违背了开发—封闭原则,其主要原因是由于switch的判断结构的使用,使修改或添加新的对象时需要改动简单工厂类的代码 ...

  6. 大话设计模式C++版——简单工厂模式

    简单工厂模式应该是所有设计模式中最简单,也最基础的一种模式,以下是一个简单的采用工厂模式写一个加减法的计算器. 1.抽象接口类——依赖倒转原则(高层和底层都要依赖于抽象,针对接口编程) class I ...

  7. 大话设计模式C++版——原则和引言

    转贴请注明转自:http://blog.csdn.net/gufeng99/article/details/45832711 读程杰的<大话设计模式>有一段时间了,将其C#版的设计模式代码 ...

  8. 大话设计模式Python实现-装饰模式

    装饰模式(Decorator Pattern):动态的给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活. 下面是一个给人穿衣服的过程,使用装饰模式: #!/usr/bin/en ...

  9. 大话设计模式C++版——观察者模式

    观察者模式是一种类似于消息分发的模式,用于一个任务需要被多个对象监听的场景,或者成员对象需要反向通知类对象的情况,是一种很有用的设计模式.    这里以大话设计模式中的例子为例,办公室员工A.B.C在 ...

随机推荐

  1. One Page Scroll – 实现苹果风格的单页滚动效果

    单页滚动网站已经被广泛使用了有一段时间了,它们对于快速提供信息是很有用的.One Page Scroll 是一个 jQuery 插件,简化了创建此类网站的步骤,只需创建 HTML 结构,进行简单设置, ...

  2. 使用 WordPress 主题制作的20个精美网页

    WordPress 是一款个人博客系统,并逐步演化成一款内容管理系统软件,它是使用 PHP 语言和 MySQL 数据库开发的.用户可以在支持 PHP 和 MySQL 数据库的服务器上使用自己的博客.这 ...

  3. sql搜索数据库中具有某列的表

    在接口中明明有某个节点,但在数据库中却找不到,为此本人写了一个sql,以供快速查找. Select distinct syscolumns.name,sysobjects.name from sysc ...

  4. Python正则表达式使用实例

    最近做题需要使用正则表达式提取信息,正则表达式很强大,之前都是纸上谈兵,这次刚好动动手,简单实现下: 文本内容如下: var user={star: false, vip :false}; var f ...

  5. yum源的配置(centos6.5)

    # cd /etc/yum.repos.d/ # mv CentOS-Base.repo CentOS-Base.repo.bak # wget http://mirrors.163.com/.hel ...

  6. Laravel 5 性能优化技巧

    说明 性能一直是 Laravel 框架为人诟病的一个点,所以调优 Laravel 程序算是一个必学的技能. 接下来分享一些开发的最佳实践,还有调优技巧,大家有别的建议也欢迎留言讨论. 这里是简单的列表 ...

  7. Android 调用已安装市场,进行软件评分的功能实现

    Uri uri = Uri.parse("market://details?id="+getPackageName()); Intent intent = new Intent(I ...

  8. 对抽屉效果几大github第三方库的调研

    在公司项目新版本方案选择中,对主导航中要使用的抽屉效果进行了调研.主要原因是旧的项目中所用的库ECS评价不是很好.现对当下比较火的几大热门抽屉效果的第三方库进行了调研.代码全部选自github 如果你 ...

  9. 操作系统开发系列—13.c.进程之中断重入

    现在又出现了另外一个的问题,在中断处理过程中是否应该允许下一个中断发生? 让我们修改一下代码,以便让系统可以在时钟中断的处理过程中接受下一个时钟中断.这听起来不是个很好的主意,但是可以借此来做个试验. ...

  10. 操作系统开发系列—12.c.从Loader加载ELF内核,顺便解释下函数调用过程 ●

    实际上,我们要做的工作是根据内核的Program header table的信息进行类似下面这个C语言语句的内存复制: memcpy(p_vaddr, BaseOfLoaderPhyAddr+p_of ...