1、 Decorator模式簡介
《設計模式》一書中對Decorator模式的意圖是這樣敘述的:
動態的給一個對象添加一些額外的職責。就增加功能來說,Decorator模式比生成子類更爲靈活。
Decorator模式的工作原理是:可以創建始於Decorator對象(負責新功能的對象)終於原對象的一個對象“鏈”。實現方法:將原對象作爲新對象的成員。
如上圖中Decorator模式的類圖隱含了一條對象鏈。每條鏈都始於一個Component對象(ConcreteComponent或Decorator)。每個Decorator對象後面都跟着另一個Decorator對象或原ConcreteComponent對象。對象鏈總是終於一個ConcreteComponent對象。
例如,在上圖中,ConcreteDecoratorB對象執行其Operation方法,然後調用Decorator類的Operation方法。這又將調用ConcreteDecoratorB對象之後的Component對象的Operation方法。
上圖爲設置表頭和頁腳的Decorator模式類圖,如果需要這樣的一張票據:
Header1
Header2
Sales Ticket
Footer1
則實現代碼:
Component * pComponent = new Header1(newHeader2(new Foorer1(new SalesTicket())));
pComponent->prtTicket();
2、 Decorator模式關鍵特徵
意圖 |
動態地給一個對象添加職責 |
問題 |
要使用的對象將執行所需基本功能。但是,可能需要爲這個對象將添加某些功能,這些附加功能可能發生在對象的基礎功能之前或之後。 |
解決方案 |
可以無需創建子類,而擴展一個對象的功能 |
參與者與協作者 |
ConcreteComponent讓Decorator對象爲自己添加功能。有時候用ConcreteComponent的派生類提供核心功能,在這種情況下ConcreteComponent類就不再是具體的,而是抽象的。Component類定義了所有這些類所使用的接口。 |
效果 |
所添加的功能放在小對象中。好處是可以在ConcreteComponent對象功能之前或之後動態添加功能。注意,雖然裝飾對象可以在被裝飾對象之前或之後添加功能,但對象鏈總是終於ConcreteComponent對象。 |
實現 |
創建一個抽象類來表示原類和要添加到這個類的功能。在裝飾類中,將對新功能的調用放在對緊隨其後對象的調用之前或之後,以獲得正確的順序。 |
3、 Decorator模式的本質
Decorator模式的使用場合是:各種可選功能在另一個肯定要執行的功能之前或之後執行。
上述Decorator模式的實現實際上是一種很糟糕的設計。例如,假設這些“裝飾對象”(即可選功能)是由不同的開發組開發的,而且系統可能拋出一些異常,需要由每個裝飾對象進行處理。理想情況下,可以相信這些開發組都能夠按預期地實現—正確地捕獲這些異常。然而,如果他們沒有做到會怎麼樣呢?如果一個異常拋出了,而某個開發組編寫的代碼無法捕獲它,整個系統這時可能crash。
另一種方案是讓客戶對象捕獲異常。但是,這也就喪失了Decorator模式的價值,因爲客戶類需要完成比它以前更多的任務。
更健全的解決方案是實現一個與ConcreteComponent對象接口相同的對象集合。它調用裝飾對象,捕獲後者沒有捕獲的任何必須捕獲的異常。事實上,這可能具有附加的好處:裝飾對象再也不必要與ConcreteComponent對象接口相同了。
關鍵在於,Decorator模式有如下約束因素:
- 存在幾種可選功能;
- 這些裝飾對像可能遵循也可能不遵循所有規則;
- 需要某種方式以所需的不同順序調用這些裝飾對象,但是又不能加重客戶對象的負擔;
- 不希望應用程序必須承擔知道使用哪些裝飾對象(甚或是否存在)的職責。
這樣思考Decorator模式將使模式的意圖和實現分離開來。