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

class CDress
{
public:
virtual ~CDress() {} virtual void Show()
{
printf("dressed boy.\n");
}
};

2、装饰类基类

class CFinery : public CDress
{
public:
CFinery() : m_poDress(NULL) {}
virtual ~CFinery() {} virtual void Show()
{
if (m_poDress)
{
m_poDress->Show();
}
} void Decorate(CDress* poCDress)
{
m_poDress = poCDress;
} private:
CDress* m_poDress;
};

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

class CTShirt : public	CFinery
{
public:
virtual ~CTShirt() {} void Show()
{
printf("Tshirt ");
CFinery::Show();
}
}; class CJeans : public CFinery
{
public:
virtual ~CJeans() {} void Show()
{
printf("Jeans ");
CFinery::Show();
}
};

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

4、装饰过程

int main(int argc, char* argv[])
{
CDress oCDress;
CTShirt oCTShirt;
CJeans oCJeans; oCTShirt.Decorate(&oCDress);
oCJeans.Decorate(&oCTShirt);
oCJeans.Show(); return 0;
}

通过装饰过程可以看出,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. 一种基于annotation的Spring-mvc权限控制方法

    简介 本文介绍一种采用annotation来对spring-mvc进行权限控制的方法. 通过枚举类来定义权限项. 将annotation标注到需要控制权限的spring-mvc方法上. 然后,在spr ...

  2. Redis 3.2.1集群搭建

    一.概述 Redis3.0版本之后支持Cluster. 1.1.redis cluster的现状 目前redis支持的cluster特性: 1):节点自动发现 2):slave->master ...

  3. 【Spring】Spring框架之Struts2和Spring的优点

    Java Web开发使用Structs2和Spring框架的好处 今年我一直在思考web开发里的前后端分离的问题,到了现在也颇有点心得了,随着这个问题的深入,再加以现在公司很多web项目的控制层的技术 ...

  4. .net c# 视频剪切抓取缩略图

    public string Cut(string ffmpegPath, string videoPath, string savePath, string imgSize, int sleepTim ...

  5. JavaScript的运动框架学习总结

    一.目录 1. 入门案例——实现匀速运动 2. 入门案例——实现缓冲运动 3. 实现任意值的运动框架v.1 4. 改进任意值的运动框架v.2 5. 改进任意值的运动框架v.3 6. 实现链式运动框架 ...

  6. SubSonic2.2框架的使用方法和配置说明

    网上.net ORM框架也不少,但是我感觉这个框架配置很简单的,前几年貌似用的人很多,现在好像用得比较少了,随着它官方的升级现在已经到3.0了, 并且采用T4 模板生成的方式,代码量好像减少了.不过我 ...

  7. AngularJS结合RequireJS做文件合并压缩的那些坑

    我在项目使用了AngularJS框架,用RequireJS做异步模块加载(AMD),在做文件合并压缩时,遇到了一些坑,有些只是解决了,但不明白原因. 那些坑 1. build.js里面的paths必须 ...

  8. 微信 小程序 drawImage wx.canvasToTempFilePath wx.saveFile 获取设备宽高 尺寸问题

    以下问题测试环境为微信开发者0.10.102800,手机端iphone6,如有不对敬谢指出. 根据我的测试,context.drawImage,在开发者工具中并不能画出来,只有预览到手机中显示. wx ...

  9. OpenGL中旋转平移缩放等变换的顺序对模型的影响

    l 前提: 0x01. 假设绘制顶点的语句为Draw Array,变换的语句(旋转.平移.缩放)为M,而 M0; M1; M2; Draw Array; 则称对Array先进行M2再进行M1.M0 0 ...

  10. 实验9:Problem G: 克隆人来了!

    想要输出""的话: cout<<"A person whose name is \""<<name<<" ...