DECORATOR中文的意思是装饰,该模式的动机是帮助对象动态的添加一些功能。它强调是为对象而不是为类添加功能。为类添加功能最有效的方式是通过继承来实现,但继承的缺点是不够灵活。下面我们还是通过例子来理解该模式。

十年生死两茫茫,不思量,自难忘。
    千里孤坟,无处话凄凉。
    纵使相逢应不识,尘满面,鬓如霜。
    
    夜来幽梦忽还乡,小轩窗,正梳妆。
    相顾无言,惟有泪千行。
    料的年年断肠处,明月夜,短松冈。
    
     挺喜欢这首词的,是我能背下来的不多的几首词中的一首。这是苏东坡为亡妻王弗写的一首悼亡诗。王弗十六岁时嫁给苏轼,婚后夫妻恩爱。苏轼的《亡妻墓志铭》中写到:“见轼读书,则终日不去。”颇有“红袖添香夜伴读”之味。可惜正如苏轼的《明月几时有》中写的一样:“人有悲欢离合,月有阴晴圆缺,此事古难全。”王氏于二十七岁时病逝,苏轼悲痛万分。十年后的一个夜晚,苏轼又一次在梦中梦到了与妻子往日的缠绵,醒来后不禁泪下,写下了这首词。
    前两天,和一兄弟网上聊天。他说自己陷入情网,无法自拔,痛苦万分。问他什么原因?他说自己爱上了一个女孩,但人家已经有了男朋友;看着年龄越来越大,找到自己合适的伴侣是越来越难。为了给他雪上加霜,我劝他死心吧,找到合适的概率太小;不如等到那天混的可以了,有房子后,发个征婚启示什么的,然后就可以直接结婚了。他坚决的拒绝了我给他的友好建议,说看到很多结婚的朋友,为了鸡毛蒜皮的小事而吵架,一点意思都没有;与其这样,还不如自己一个人。是啊,随着工业文明的进步,人的神经也被不断的拉紧,少了农耕时代的悠闲。我们的生活越来越匆忙,少了欣赏美的情趣,生活中的点点滴滴的美,有多少人可以体验得到?“小轩窗,正梳妆”,古人可以体会得到的美,而在我们的字典里能找到吗?为了些须小事而吵架分离,婚姻不再是“围城”,令城外的我们也忘而却步。很多人都在等待,等待那份不会因物质而庸俗化的爱情,能等到吗?“但愿人长久,千里共婵娟”,将此祝福天下所有期望这份爱情的人。
    好了,我们来描述我们的例子吧。考虑一下美女梳妆的情景,她会盘弄自己的头发,填加首饰在自己头上,可能还有耳环一类的东西。但每个美女身上的饰物并不相同,我们为美女提供一个类的话,如何可以做到让她们的饰物各不相同呢?好的,我们还是一步一步来,首先抽象出一个美女类:

这个类比较简单,就是画一个美女出来(不好意思,这里仍然是用文字意思一下,不熟悉图象处理;真希望能真正画一个出来,什么时候有时间好好学学)。我们再来看如何帮美女填加饰物,仍是先看传统的方式:

那么需要填加这样的变量m_IsHasHair(什么,美女可以没有头发?当然可以,不信可以找金庸的《笑傲江湖》来看看),m_IsHasNeaklace(项链),m_IsEarbob(耳环)。那么我们的Draw的实现就需要根据不同的条件来实现,大概的代码如下:

Void Draw()
{   
    ……画一个美女    
    If( m_IsHasHair){      
        …….  
    }  
    
    If ( m_IsHasNeakLace){   
        ……..  
    }  
    
    If ( m_IsEarbob){
           …….. 
    }
}

还是结构化的东西,我们需要考虑的问题是:当新的饰物需要填加到类中的时候,我们该如何处理?再次强调面向对象的基本原则:一个模块对扩展应该是开放的,对修改应该是关闭的。如果按现在的做法,我们不得不再次打开Draw为它添加新的条件,实现新的功能。这个方案被否决,那么我优先考虑到的还是继承,看它能不能完成我们的功能?

如上类图,我们试图使用继承的方法来实现该功能。当新加装饰类型的时候,是可以做到不需改变以前的代码。但新的问题又来,当一个美女既有头发又有项链的时候,我们该怎么办。那么通过继承的方法就是新加一个类:BeautyWithHairAndNeakLace,如果一个一个条件组合下去,类又失去了控制,又是类爆炸现象。简单的继承无法完成我们的功能。还好,如果你知道了Decorator模式,问题就会变的简单起来。我们首先来看看Decorator模式的类图。

对该类图,做一些说明:
    1, 我们需要为我们要用到的类和它所需要的包装类提供一个共同的接口:Component。
    2, ConcreteComponent是我们要用到的类,就是需要为该类的对象动态的填加一些功能进去。
    3, Decorator是我们要用到的包装类,它也应该是一个抽象类,我们是通过它的子类来实现对ConcreteComponent的包装。每个Decorator子类的实例都应该拥有一个指向Component的指针或引用。
    4, ConcreteDecoratorA和ConcreteDecoratorB是我们用来包装的实类,它拥有一个指向Component的实例。我们可以在该类中填加新的类型和方法,但这些类型和方法只能在类内部使用,因为该类的调用是通过Component接口来实现的。
     好了,看完该类图,你是否对该模式还是不清楚?没关系,看到实际的代码后,一切就清晰了。我们再按该模式来设计我们的美女类图:

帮我们的美女抽象出一个接口:BeautyInterface。Beauty继承自BeautyInterface是我们实际要用到的类。而BeautyDecorator是我们抽象出的装饰类。Hair,Necklace,Earbob是要具体用来装饰的类,可以看到他们重载了Draw,调用接口的Draw并且填加一些自己的功能进去。具体该如何用呢?来看代码。

//美女接口    
class BeautyInterface    
{    
public:    
    virtual void Draw() = 0;
};

//美女实类    
class Beauty : public BeautyInterface    
{    
public:        
    void Draw()
    { 
        cout << "This is a beauty!" << endl;
    }    
};

//美女装饰类    
class BeautyDecorator : public BeautyInterface    
{    
public:        
    virtual void Draw() = 0;    
};

//头发类    
class Hair : public BeautyDecorator    
{    
private:        
    BeautyInterface *m_pBeauty;

public:        
    Hair(BeautyInterface *pBeauty):m_pBeauty(pBeauty){}        
    
    void Draw()        
    {             
        m_pBeauty->Draw();    
        DrawHair();        
    }

private:        
    void DrawHair()    
    {            
        cout << "Hi,this is my beautiful hair!" << endl;    
    }    
};

//项链类    
class Neaklace : public BeautyDecorator
{    
private:    
    BeautyInterface *m_pBeauty;    
public:        
    Neaklace(BeautyInterface *pBeauty):m_pBeauty(pBeauty){}

void Draw()        
    {             
        m_pBeauty->Draw();            
        DrawNeaklace();        
    }    
private:
    void DrawNeaklace()    
    {            
        cout << "Hi,look at my neaklace!" << endl;
    }    
};

//耳环类    
class Earbob : public BeautyDecorator    
{    
private:    
    BeautyInterface *m_pBeauty;

public:        
    Earbob(BeautyInterface *pBeauty):m_pBeauty(pBeauty){}    
    void Draw()    
    {         
        m_pBeauty->Draw();        
        DrawEarbob();    
    }

private:    
    void DrawEarbob()    
    {        
        cout << "Hi,look at my Earbob!" << endl;    
    }    
}

好了,这就是我们要实现的类代码。我们需要注意的是Hair等装饰类的构造函数,需要初始化一个BeautyInterface 接口指针。 
        Hair(BeautyInterface *pBeauty):m_pBeauty(pBeauty){}

我们再来看看该类的具体应用:

int main(int argc, char* argv[])
{ 
    BeautyInterface *pBeauty = new Earbob(new Neaklace(new Hair(new Beauty))); 
    pBeauty->Draw();    
    delete pBeauty;  
    return 0;
}

编译后的运行结果如下:

这就是DECORATOR模式的具体使用了,下次我们接着聊COMPOSITE模式。

乱砍设计模式之三 -- DECORATOR模式相关推荐

  1. 乱砍设计模式之一 -- STRATEGY 模式

    转自 : http://www.vckbase.com/document/viewdoc/?id=1633 STRATEGY在中文中被译成了策略,我感觉这个意思并不妥切,但翻英文词典能得到的翻译也只有 ...

  2. 乱砍设计模式之一 -- STRATEGY模式

    STRATEGY模式---赵子龙单骑救主 junguo STRATEGY在中文中被译成了策略,我感觉这个意思并不妥切,但翻英文词典能得到的翻译也只有这个,我的词典比较简单,不知道是否还有其它意思?如果 ...

  3. 乱砍设计模式之二 -- STATE模式

    转自 : http://blog.csdn.net/wishfly/archive/2008/01/22/2060026.aspx STATE模式的中文名称是状态模式.在<设计模式>一书中 ...

  4. 设计模式:装饰(Decorator)模式

    设计模式之装饰(Decorator)模式 在现实生活中,常常需要对现有产品增加新的功能或美化其外观,如房子装修.相片加相框等.在软件开发过程中,有时想用一些现存的组件.这些组件可能只是完成了一些核心功 ...

  5. 三国演义与设计模式之Decorator模式(1.虎牢关三英战吕布 2.云长降曹受封赏)...

     写在前面: 以下三点,适用于本系列所有文章. 1.同一个故事,从不同的角度看,就可以引申出不同的模式.本系列中所举模式,未必是当前故事是匹配的,还望大家多提意见,一起讨论,一起提高. 2.类图部分只 ...

  6. Java--23种设计模式之decorator模式

    装饰模式:装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案,提供比继承更多的灵活性.动态给一个对象增加功能,这些功能可以再动态的撤消.增加由一些基本功能的排列组合而产生的非常大量的 ...

  7. java 设计模式之三-模版模式

    新的一天,天气不错,坚持.努力.加油! 今天想说的是模版模式,其实这个模式大家都常用,只是可能不知道还有"模版模式"这么一个称呼而已,使用继承的方式来实现,父类为模版,子类根据不同 ...

  8. Decorator模式------装饰边框与被装饰物的一致性

    1. >>不断地为对象装饰的设计模式称为Decorator 模式. 2. 示例程序 >>功能:给文字添加装饰边框.这里所谓的装饰边框是指用" - " &qu ...

  9. 设计模式-Decorator模式

    目录 一个例子(贪玩蓝月) 传统继承实现 装饰器模式实现 对比 总结 Decorator(装饰器)模式属于结构型模式. 比如当其需要三种不同的附加特性,可以为其创建三个派生类.但是若它还需要同时具有其 ...

最新文章

  1. Yarn基本架构和工作机制
  2. vue中解决时间在ios上显示NAN的问题
  3. nginx负载均衡的策略
  4. 重新抛出异常与异常链
  5. python class函数报错_Python multiprocess pool模块报错pickling error问题解决方法分析
  6. 邮件发送---SpringBoot
  7. LeetCode 189. 旋转数组(环形替换)
  8. kill 进程_如何查杀stopped进程
  9. 循环计数_倒计数器:CountDownLatch | 循环栅栏:CyclicBarrier
  10. 01_决策树案例一:鸢尾花数据分类
  11. Selenium分布式运行:SeleniumGrid
  12. Qt5.X 在Arm上LinuxFB平台旋转显示
  13. 面向未来的100项颠覆性创新技术!欧盟重磅报告
  14. 数据库相关类型(日期、复合、bit、布尔)
  15. Unity中使用模板测试模拟Mask组件效果
  16. IOS逆向(1)IOS越狱
  17. ヴィアッカ / 风锤
  18. Numpy:随机抽样
  19. Unity3D研究院之在MAC上脚本XlsxWriter写入Excel .xlsx格式
  20. Alextnet网络

热门文章

  1. 归一化数字角频率_数字信号处理中的各种频率
  2. 百度目前开放的AI平台
  3. 曾经的中国互联网:多少巨头销声匿迹
  4. everbox邀请码和麦库邀请码
  5. Java爬取并下载酷狗TOP500歌曲
  6. 2012年4月编程语言排行榜:C语言重返第一
  7. 为什么iPhone手机微信信息老是出现延误?原来是这5大原因搞的鬼
  8. 地址栏中输入网址后发生了什么?
  9. 远程监控技术计算机网络,计算机网络技术视角下的远程监控技术研究
  10. STG游戏中瞄具的基本原理