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