裝飾模式:
動態地給一個對象添加一些額外的職責。就增加功能來說,Decorator模式相比產生子類更為靈活。
.NET中應用:
public abstract class Log
{
public abstract void Write(string log);
}
public class DatabaseLog : Log
{
public override void Write(string log)
{
//......記錄到資料庫中
}
}
public class TextFileLog : Log
{
public override void Write(string log)
{
//......記錄到文字檔中
}
}
public abstract class LogWrapper : Log
{
private Log _log;
public LogWrapper(Log log)
{
_log = log;
}
public override void Write(string log)
{
_log.Write(log);
}
}
public class LogErrorWrapper : LogWrapper
{
public LogErrorWrapper(Log _log)
:base(_log)
{
}
public override void Write(string log)
{
SetError(); //......功能擴充
base.Write(log);
}
public void SetError()
{
//......實現了記錄錯誤嚴重層級
}
}
public class LogPriorityWrapper : LogWrapper
{
public LogPriorityWrapper(Log _log)
: base(_log)
{
}
public override void Write(string log)
{
SetPriority(); //......功能擴充
base.Write(log);
}
public void SetPriority()
{
//......實現了記錄優先順序別
}
}
到這裡,LogErrorWrapper類和LogPriorityWrapper類真正實現了對錯誤嚴重層級和優先順序別的功能的擴充。我們來看一下客戶程式如何去調用它:
public class Program
{
public static void Main(string[] args)
{
Log log = new DatabaseLog();
LogWrapper lew1 = new LogErrorWrapper(log);
//擴充了記錄錯誤嚴重層級
lew1.Write("Log Message");
LogPriorityWrapper lpw1 = new LogPriorityWrapper(log);
//擴充了記錄優先順序別
lpw1.Write("Log Message");
LogWrapper lew2 = new LogErrorWrapper(log);
LogPriorityWrapper lpw2 = new LogPriorityWrapper(lew2); //這裡是lew2
//同時擴充了錯誤嚴重層級和優先順序別
lpw2.Write("Log Message");
}
}
.NET中裝飾模式一個典型的運用就是關於Stream,它存在著如下的類結構:
圖8
System.IO.Stream 抽象類別,可以輕鬆的處理來源於文字檔(FileStream),TCP/IP網路通訊(NetworkStrem)或者是其他的實體等的資料,而不管這些資料的來源,下面是一個將流中的位元組輸出到控制台的方法:
public static void PrintBytes(Stream s)
{
int b;
while((b = fs.ReadByte()) >= 0)
{
Console.Write(b + " ");
}
}
從流中一次讀取一個位元組不是一個非常有效方式,例如:硬體能夠(也是最適合的)連續的把資料區塊從磁碟中讀到一個大的塊中,如果你知道準備要讀取一些字元,比較好的方法是將資料區塊一次性的從磁碟中取出後在記憶體中處理這些字元,在net Framework裡,BufferedStream類負責處理這種操作,BufferedStream類的構造只有一個參數,這個參數可以是任何一個需要緩衝處理的流對象, BufferedStream類重載了Stream的許多方法,比如Read和Write,憑此來提供更強大的功能(這個功能其實就是緩衝了,譯者注)。因為
BufferedStream是Stream 類的子類,所以你可以像使用其它Stream類一樣使用它。(值得注意的是FileStream已經內建了自己緩衝功能)
同樣的,你可以使用System.Security.Cryptography.CryptoStream類隨意的對任何流對象進行加密和解密。下面的例子展示了使用幾種不同類型的流對象來調用我的列印方法:
MemoryStream ms = new MemoryStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}); ------〉 PrintBytes(ms);
BufferedStream buff = new BufferedStream(ms); ------〉 PrintBytes(buff);
buff.Close();
FileStream fs = new FileStream("../../decorator.txt", FileMode.Open); ------〉 PrintBytes(fs); fs.Close();
這種通過組合方式無縫的,動態給對象添加功能的能力就是裝飾模式的一個例子。就像所展示的那樣:
對於每一個Stream的執行個體,你可以通過將Stream封裝成BufferedStream來給Stream來添加緩衝功能,而不需要改變資料的介面(就是Stream類型的介面,譯者注),因為僅僅是組合對象(比如FileStream執行個體作為一個參數傳給BufferedStream執行個體的構造子後,這個BufferedStream就是一個具有緩衝功能的FileStream執行個體,其他流執行個體也可以通過這種操作來擴充自己的功能,這就是裝飾模式的精髓所在!譯者注),這種方式比在編譯時間繼承某一具體的流類型來得更加的優雅(比如,如果使用繼承的方式,FileStream為了實現緩衝功能,而不得不有一個繼承FileStream類的有緩衝功能的子類,這種方式的最大的問題是使整個繼承樹變得非常的臃腫,譯者注),因為前一種方式可以在運行時實現!裝飾模式核心的功能是所有的裝飾者都實現了某介面或者重載了某一個抽象基類(比如Stream抽象基類)並提供了格外的功能。比如:
BufferedStream重載了Read方法來提供從一個緩衝區讀取的功能,而不是直接象其他流一樣直接讀取資料。就像前一個例子,任何一個組合成的裝飾者,不管它有多麼的複雜,還是和它的基類一樣提供同樣的功能。
其中BufferedStream與CryptoStream就是裝飾者模式中的裝飾者:為其他Stream對象提供格外的功能。
參考:http://www.cnblogs.com/zhongkeruanjian/archive/2006/03/20/353959.html
http://terrylee.cnblogs.com/archive/2006/03/01/340592.html