DECORATOR中文的意思是裝飾,該模式的動(dòng)機(jī)是幫助對象動(dòng)態(tài)的添加一些功能。它強(qiáng)調(diào)是為對象而不是為類添加功能。為類添加功能最有效的方式是通過繼承來實(shí)現(xiàn),但繼承的缺點(diǎn)是不夠靈活。下面我們還是通過例子來理解該模式。 十年生死兩茫茫,不思量,自難忘。 千里孤墳,無處話凄涼。 縱使相逢應(yīng)不識,塵滿面,鬢如霜。 夜來幽夢忽還鄉(xiāng),小軒窗,正梳妝。 相顧無言,惟有淚千行。 料的年年斷腸處,明月夜,短松岡。 挺喜歡這首詞的,是我能背下來的不多的幾首詞中的一首。這是蘇東坡為亡妻王弗寫的一首悼亡詩。王弗十六歲時(shí)嫁給蘇軾,婚后夫妻恩愛。蘇軾的《亡妻墓志銘》中寫到:“見軾讀書,則終日不去。”頗有“紅袖添香夜伴讀”之味??上д缣K軾的《明月幾時(shí)有》中寫的一樣:“人有悲歡離合,月有陰晴圓缺,此事古難全。”王氏于二十七歲時(shí)病逝,蘇軾悲痛萬分。十年后的一個(gè)夜晚,蘇軾又一次在夢中夢到了與妻子往日的纏綿,醒來后不禁淚下,寫下了這首詞。 前兩天,和一兄弟網(wǎng)上聊天。他說自己陷入情網(wǎng),無法自拔,痛苦萬分。問他什么原因?他說自己愛上了一個(gè)女孩,但人家已經(jīng)有了男朋友;看著年齡越來越大,找到自己合適的伴侶是越來越難。為了給他雪上加霜,我勸他死心吧,找到合適的概率太??;不如等到那天混的可以了,有房子后,發(fā)個(gè)征婚啟示什么的,然后就可以直接結(jié)婚了。他堅(jiān)決的拒絕了我給他的友好建議,說看到很多結(jié)婚的朋友,為了雞毛蒜皮的小事而吵架,一點(diǎn)意思都沒有;與其這樣,還不如自己一個(gè)人。是啊,隨著工業(yè)文明的進(jìn)步,人的神經(jīng)也被不斷的拉緊,少了農(nóng)耕時(shí)代的悠閑。我們的生活越來越匆忙,少了欣賞美的情趣,生活中的點(diǎn)點(diǎn)滴滴的美,有多少人可以體驗(yàn)得到?“小軒窗,正梳妝”,古人可以體會得到的美,而在我們的字典里能找到嗎?為了些須小事而吵架分離,婚姻不再是“圍城”,令城外的我們也忘而卻步。很多人都在等待,等待那份不會因物質(zhì)而庸俗化的愛情,能等到嗎?“但愿人長久,千里共嬋娟”,將此祝福天下所有期望這份愛情的人。 好了,我們來描述我們的例子吧??紤]一下美女梳妝的情景,她會盤弄自己的頭發(fā),填加首飾在自己頭上,可能還有耳環(huán)一類的東西。但每個(gè)美女身上的飾物并不相同,我們?yōu)槊琅峁┮粋€(gè)類的話,如何可以做到讓她們的飾物各不相同呢?好的,我們還是一步一步來,首先抽象出一個(gè)美女類: 這個(gè)類比較簡單,就是畫一個(gè)美女出來(不好意思,這里仍然是用文字意思一下,不熟悉圖象處理;真希望能真正畫一個(gè)出來,什么時(shí)候有時(shí)間好好學(xué)學(xué))。我們再來看如何幫美女填加飾物,仍是先看傳統(tǒng)的方式: 那么需要填加這樣的變量m_IsHasHair(什么,美女可以沒有頭發(fā)?當(dāng)然可以,不信可以找金庸的《笑傲江湖》來看看),m_IsHasNeaklace(項(xiàng)鏈),m_IsEarbob(耳環(huán))。那么我們的Draw的實(shí)現(xiàn)就需要根據(jù)不同的條件來實(shí)現(xiàn),大概的代碼如下: Void Draw() { ……畫一個(gè)美女 If( m_IsHasHair) { ……. } If ( m_IsHasNeakLace) { …….. } If ( m_IsEarbob) { …….. } } 還是結(jié)構(gòu)化的東西,我們需要考慮的問題是:當(dāng)新的飾物需要填加到類中的時(shí)候,我們該如何處理?再次強(qiáng)調(diào)面向?qū)ο蟮幕驹瓌t:一個(gè)模塊對擴(kuò)展應(yīng)該是開放的,對修改應(yīng)該是關(guān)閉的。如果按現(xiàn)在的做法,我們不得不再次打開Draw為它添加新的條件,實(shí)現(xiàn)新的功能。這個(gè)方案被否決,那么我優(yōu)先考慮到的還是繼承,看它能不能完成我們的功能? 如上類圖,我們試圖使用繼承的方法來實(shí)現(xiàn)該功能。當(dāng)新加裝飾類型的時(shí)候,是可以做到不需改變以前的代碼。但新的問題又來,當(dāng)一個(gè)美女既有頭發(fā)又有項(xiàng)鏈的時(shí)候,我們該怎么辦。那么通過繼承的方法就是新加一個(gè)類:BeautyWithHairAndNeakLace,如果一個(gè)一個(gè)條件組合下去,類又失去了控制,又是類爆炸現(xiàn)象。簡單的繼承無法完成我們的功能。還好,如果你知道了Decorator模式,問題就會變的簡單起來。我們首先來看看Decorator模式的類圖。 對該類圖,做一些說明: 1, 我們需要為我們要用到的類和它所需要的包裝類提供一個(gè)共同的接口:Component。 2, ConcreteComponent是我們要用到的類,就是需要為該類的對象動(dòng)態(tài)的填加一些功能進(jìn)去。 3, Decorator是我們要用到的包裝類,它也應(yīng)該是一個(gè)抽象類,我們是通過它的子類來實(shí)現(xiàn)對ConcreteComponent的包裝。每個(gè)Decorator子類的實(shí)例都應(yīng)該擁有一個(gè)指向Component的指針或引用。 4, ConcreteDecoratorA和ConcreteDecoratorB是我們用來包裝的實(shí)類,它擁有一個(gè)指向Component的實(shí)例。我們可以在該類中填加新的類型和方法,但這些類型和方法只能在類內(nèi)部使用,因?yàn)樵擃惖恼{(diào)用是通過Component接口來實(shí)現(xiàn)的。 好了,看完該類圖,你是否對該模式還是不清楚?沒關(guān)系,看到實(shí)際的代碼后,一切就清晰了。我們再按該模式來設(shè)計(jì)我們的美女類圖: 幫我們的美女抽象出一個(gè)接口:BeautyInterface。Beauty繼承自BeautyInterface是我們實(shí)際要用到的類。而BeautyDecorator是我們抽象出的裝飾類。Hair,Necklace,Earbob是要具體用來裝飾的類,可以看到他們重載了Draw,調(diào)用接口的Draw并且填加一些自己的功能進(jìn)去。具體該如何用呢?來看代碼。 //美女接口 class BeautyInterface { public: virtual void Draw() = 0; }; //美女實(shí)類 class Beauty : public BeautyInterface { public: void Draw(){ cout << "This is a beauty!" << endl;} }; //美女裝飾類 class BeautyDecorator : public BeautyInterface { public: virtual void Draw() = 0; }; //頭發(fā)類 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; } }; //項(xiàng)鏈類 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; } }; //耳環(huán)類 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; } }; 好了,這就是我們要實(shí)現(xiàn)的類代碼。我們需要注意的是Hair等裝飾類的構(gòu)造函數(shù),需要初始化一個(gè)BeautyInterface 接口指針。 Hair(BeautyInterface *pBeauty):m_pBeauty(pBeauty){} 我們再來看看該類的具體應(yīng)用: int main(int argc, char* argv[]) { BeautyInterface *pBeauty = new Earbob(new Neaklace(new Hair(new Beauty))); pBeauty->Draw(); delete pBeauty; return 0; } 編譯后的運(yùn)行結(jié)果如下: 這就是DECORATOR模式的具體使用了,下次我們接著聊COMPOSITE模式。 參考書目: 1, 設(shè)計(jì)模式——可復(fù)用面向?qū)ο筌浖幕A(chǔ)(Design Patterns ——Elements of Reusable Object-Oriented Software) Erich Gamma 等著 李英軍等譯 機(jī)械工業(yè)出版社 2, Head First Design Patterns(影印版)Freeman等著 東南大學(xué)出版社 3, 道法自然——面向?qū)ο髮?shí)踐指南 王詠武 王詠剛著 電子工業(yè)出版社 |
|