技术开发 频道

结构型模式篇-装饰模式(Decorator Pattern)



    其次,随着以后扩展功能的增多,子类会迅速的膨胀,可以看到,子类的出现其实是DatabaseLog和TextFileLog两个子类与新增加的接口的一种排列组合关系,所以类结构会变得很复杂而难以维护,正如象李建忠老师说的那样“子类复子类,子类何其多”;最后,这种方式的扩展是一种静态的扩展方式,并没有能够真正实现扩展功能的动态添加,客户程序不能选择添加扩展功能的方式和时机。

    现在又该是Decorator模式出场的时候了,解决方案是把Log对象嵌入到另一个对象中,由这个对象来扩展功能。首先我们要定义一个抽象的包装类LogWrapper,让它继承于Log类,结构图如下:



                                                       图6

实现代码如下:

public abstract class LogWrapper : Log { private Log _log; public LogWrapper(Log log) { _log = log; } public override void Write(string log) { _log.Write(log); } }
    现在对于每个扩展的功能,都增加一个包装类的子类,让它们来实现具体的扩展功能,如下图中绿色的区域:



                                                                                图7

实现代码如下:
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"); } }
   
    注意在上面程序中的第三段装饰才真正体现出了Decorator模式的精妙所在,这里总共包装了两次:第一次对log对象进行错误严重级别的装饰,变成了lew2对象,第二次再对lew2对象进行装饰,于是变成了lpw2对象,此时的lpw2对象同时扩展了错误严重级别和优先级别的功能。也就是说我们需要哪些功能,就可以这样继续包装下去。到这里也许有人会说LogPriorityWrapper类的构造函数接收的是一个Log对象,为什么这里可以传入LogErrorWrapper对象呢?通过类结构图就能发现,LogErrorWrapper类其实也是Log类的一个子类。

    我们分析一下这样会带来什么好处?首先对于扩展功能已经实现了真正的动态增加,只在需要某种功能的时候才进行包装;其次,如果再出现一种新的扩展功能,只需要增加一个对应的包装子类(注意:这一点任何时候都是避免不了的),而无需再进行很多子类的继承,不会出现子类的膨胀,同时Decorator模式也很好的符合了面向对象设计原则中的“优先使用对象组合而非继承”和“开放-封闭”原则。 









0
相关文章