設計模式學習之裝飾(decorator)
最近工作上遇到一個問題,最后用設計模式——裝飾模式(Decorator)解決了,加深了對這個模式的印象,記錄一下,同時當作對看書的復習吧,如果對其他朋友有拋磚引玉的作用就最好了^_^。
問題描述
我們的UI操作是一種已經定下來的模式,后來被要求修改為另外一種操作模式。簡單來說,就是要改變一種控件的功能,我們后面就把這種控件叫做WidgetBox吧。而且,這個WidgetBox類本身有別的用途,暫時不考慮直接在原來的基礎上修改。
從這個角度來說,解決這個問題首先想到的方法是: 繼承! 以WidgetBox作為父類重新寫一個子類,重載關鍵函數,滿足新操作模式的需求。
但是,恰恰遇到問題了:
- 子類需要把父類的主要功能完全重寫,需要改掉很多函數代碼,麻煩;
- 還有另外一個問題。由于界面用的是flash,在消息處理方面綁定的比較底層,已經很難改動了,除非你把整個工程中別的地方用到的都改掉,工程上這是不切實際的;
- 最重要的是:目前由于UI是flash制作的,所以在控件上有一些約定。新定義控件(反應到代碼里面也就是添加子類)雖然不麻煩,但是還要把一部分維護工作留給UI人員,是自己不想的。
所以, 繼承 這個方法行不通,會因為改動底層給系統帶來很大的不穩定性,而且代碼量和結構上的修改并沒有什么可取之處,如果需求變了,需要新的操作模式呢?
在以上的背景之下,自己想到了如此拙見:用到了裝飾(Decorator)這個設計模式。雖然不能完美解決問題,還存在缺點,但是總的來說比上面的這個方法好。如果以后再碰到更好的解決辦法,說明我又進步了。^_^
裝飾(Decorator)模式
引用書上的一句話:
動態地給一個對象添加一些額外的職責。
動機
依然引用書上的說法:
有時我們希望給某個對象而不是整個類添加一些功能。一種較為靈活的方式是將組件嵌入另一個對象中。
對接上自己需要的:
很簡單!能在不改變現有系統結構的情況下,增加一種新的操作方式。那么我就實現一個裝飾類,在其中嵌入已經存在的控件類WidgetBox,然后我在裝飾類中實現自己的各種操作方式,而且用到大部分的WidgetBox類本身已經實現的功能。
結構
完整的裝飾模式的結構如下圖所示:
但是,因為個中原因,自己的實現有些許不同:
說明一下:
- 1.沒有實現一個上層的抽象接口類,因為不想改變現有的結構。但是寫到這里的時候,覺得Decorator類可以繼承Widget類(他是WidgetBox類最上層的基類),這樣會優化下面提到的問題。同時,這也說明記錄寫文章是有一些用處滴^_^。
- 2.這個接口暴露了自己實現的一個缺點:Decorator需要完全擁有和WidgetBox一模一樣的接口,這里就留下了維護這兩個類接口一致的問題,特別是如果你想要用戶在WidgetBoxDecorator的操作和WidgetBox沒有區別的情況下。但是,上面也提到了可以繼承widget類,會大大減弱這個問題。
實現
### C++ class WidgetBox{ void subscribe(event); void unsubscribe(event); void HoldObject(); bool OnMousePress(); bool OnMouseUp(); }
class Decorator{
virtual void subscribe(event);
virtual void unsubscribe(event);
virtual void HoldObject();
virtual bool OnMousePress();
virtual bool OnMouseUp();
private:
WidgetBox* pItem;
}
class WidgetBoxDecorator{
void subscribe(event);
void unsubscribe(event);
void HoldObject();
bool OnMousePress();
bool OnMouseUp();
}
int main()
{
// 老的控件操作模式
WidgetBox *pItem = new WidgetBox("name");
pItem->HoldObject();
// 新的控件操作模式
WidgetBoxDecorator *pItem(new WidgetBox("name"));
pItem->HoldObject();
} ### 小結
- 什么時候用裝飾模式? > 1.在不影響其他對象的情況下,比如自己這里不能夠改變現有的結構; > 2.當不能采用生成子類的方法進行擴充時,自己碰到的問題也算是; > 3.書上還提到:處理那些可以撤銷的職責,這個沒有用到。
總結
自己也把《設計模式-可服用面向對象軟件的基礎》這本書看了一遍,印象其實不是很深刻,除了個別非常形象的模式之外,例如:享元模式-FlyWeight。剩下的就是自己去寫過或者常用的模式了,比如:單例模式、工廠模式、觀察者模式。所以,對于自己來說,碰到一個問題,特別是設計上的問題,然后用一個設計模式去解決這個問題,才能深刻理解這個模式的優缺點,以及用途。
參考
[1]《設計模式:可復用面向對象軟件的基礎》
學習:JavaScript實現
var WidgetBox = {
createNew: function(){
var widget = {};
widget.OnMouseUp = function()
{
console.log("WidgetBox OnMouseUp();");
}
return widget;
}
}
var Decorator = {
createNew: function(){
var widget = {};
widget.item = WidgetBox.createNew();
widget.OnMouseUp = function()
{
item.OnMouseUp();
console.log("Decorator OnMouseUp();");
}
return widget;
}
}
var WidgetBoxDecorator = {
createNew: function(){
// 繼承
var widget = Decorator.createNew();
widget.item = WidgetBox.createNew();
widget.OnMouseUp = function()
{
console.log("WidgetBoxDecorator OnMouseUp();");
}
return widget;
}
}
// old operation
console.log("Old operation:");
var item = WidgetBox.createNew();
item.OnMouseUp();
// new operation
console.log("New operation:");
var item1 = WidgetBoxDecorator.createNew();
item1.OnMouseUp();
結果:
Old operation:
WidgetBox OnMouseUp();
New operation:
WidgetBoxDecorator OnMouseUp();
來自:http://pkxpp.github.io/2017/02/12/設計模式學習之裝飾(Decorator)/