动态地给一个对象添加一些额外的职责。就增加功能来说,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