我假設看這篇文章的朋友對裝飾者模式都能有各自的、深入的了解。因為這篇文章是讨論裝飾者模式的性能問題。
首先回顧一下裝飾者模式誕生的本意是什麼,它的官方意思是:動态地給一個對象添加一些額外的職責。我們都知道給對象擴充功能是通過繼承來實作,但是繼承有它的不好之處,比如:子類與父類之間的耦合、子類的無限擴大等等。而裝飾者模式就是想利用動态的給需要擴充的對象添加功能。将需要擴充的動能獨立起來,作為一個個裝飾類,在需要的時候給對象穿上這個裝飾。
1:
<a href="http://blog.51cto.com/attachment/201107/171508616.png" target="_blank"></a>
這張類圖照這個樣子發展下去不得了,子類無限膨脹,後面需求誰都不知道。這是我們一般擴充對象的正常方法,我們來看一下裝飾者模式的原型。
2:
<a href="http://blog.51cto.com/attachment/201107/171520244.png" target="_blank"></a>
将需要擴充的功能獨立起來,當需要的時候動态的添加功能。我想這就是裝飾者名稱由來,将後期擴充的功能比喻成裝飾者,是很形象。
但是當我們帶着這張圖的原理去看代碼的時候,它的結構根本不是這樣的“幹淨”。是以說理論與實踐是分不開的。請看代碼:
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication2
{
public class ConcreteConpontent
{
public virtual void Operation()
{
Console.WriteLine("頂級待裝飾對象");
}
public virtual void Message()
Console.WriteLine("頂級對象消息");
}
public abstract class Decorator : ConcreteConpontent
protected ConcreteConpontent m_compontent;
public void SetCompontent(ConcreteConpontent com)
m_compontent = com;
public class ConcreteDecoratorA : Decorator
public override void Operation()
m_compontent.Operation();
Console.WriteLine("ConcreteDecoratorA進行了方法的動态添加");
public override void Message()
m_compontent.Message();
Console.WriteLine("ConcreteDecoratorA進行了Message方法的動态添加");
public class ConcreteDecoratorB : Decorator
Console.WriteLine("ConcreteDecoratorB進行了方法的裝飾");
Console.WriteLine("ConcreteDecoratorB進行了Message方法的動态添加");
public class ConcreteDecoratorC : Decorator
Console.WriteLine("ConcreteDecoratorC進行了方法的裝飾");
Console.WriteLine("ConcreteDecoratorC進行了Message方法的動态添加");
}
裝飾者模式的基本代碼原型差不多就這樣子的。當我看到裝飾者模式是這樣的一個代碼結構的時候,其實說心裡話我難受。裡面不是帶着繼承嗎?為什麼要繼承,心理面不忍發了點牢騷。ConcreteConpontent是被裝飾者對象,首先我們要确定要擴充的對象是可以讓我們擴充的。其實我知道繼承是為了拿到要擴充對象的行為,并且标示所有的裝飾者是屬于一種類型的,在使用的時候就可以用基類來使用所有的裝飾者。如果沒有繼承顯然是不能用基類進行統一調用的,繼承還有一個作用就是為了拿到被裝飾者的行為,用它的為操作不同的執行個體,是夠聰明的。
我假如我不需要用基類進行統一調用裝飾者,我是否就可以不繼承自被裝飾者了;為了能夠實作裝飾者的無限遞增的裝飾,我對代碼進行了簡單的修改,請看代碼:
namespace ConsoleApplication1
public virtual void message()
public abstract class Decorator
private ConcreteConpontent m_compontent;
protected Decorator decorator;
public void SetCompontent(ConcreteConpontent com, Decorator de)
decorator = de;
if (decorator != null)
decorator.Operation();
else
m_compontent.Operation();
decorator.message();
m_compontent.message();
base.Operation();
Console.WriteLine("ConcreteDecoratorA進行了方法的裝飾");
public override void message()
base.message();
Console.WriteLine("ConcreteDecoratorA進行了message方法的動态添加");
Console.WriteLine("ConcreteDecoratorB進行了message方法的動态添加");
Console.WriteLine("ConcreteDecoratorC進行了message方法的動态添加");
如果我們這是想擴充一個簡單的小功能,讓我們繼承一個很大的對象是不是有點不劃算。隻是想用被裝飾者的行為,去操作裝飾者原型執行個體。我們可以犧牲一下代碼的備援來解決這個性能問題。書上對繼承的解釋是用來避免手動輸入被裝飾者的行為代碼。我覺得這點根本沒有說服力。其實裝飾者模式是想動态的給對象添加功能、行為、職責。在使用的時候還是想通過被裝飾者進行引用所有的裝飾者執行個體,這樣才是繼承最有效的說服力。不繼承我一樣可以有同樣的行為、一樣可以實作無限遞增的嵌套裝飾者執行個體。要想執行個體套執行個體,那麼他們必須來自同一個祖先,同樣是裝飾者,要想讓裝飾者套裝飾者,那麼在裝飾者的類中需要有一個對裝飾者類型的引用,但是每一個裝飾者不可能一樣。是以必須讓他們繼承同一個基類才行,後面再多的裝飾者隻要繼承同一個基類那麼就可以互相引用。
總結:在我們選擇使用裝飾者模式的時候,需要根據自己的使用情況進行适當修改。在沒有必要的情況下不需要繼承那麼大的一個對象。
本文轉自 王清培 51CTO部落格,原文連結:http://blog.51cto.com/wangqingpei557/622150,如需轉載請自行聯系原作者