模式定义
面向对象的其中一个重要概念就是继承。通过子类继承父类来扩充父类不具备的属性与方法,这个过程是在编译期完成的。假设我们现在需要一个不一样的功能,动态地扩充父类的方法,或者扩充其中一个子类的方法,或者组合各个子类的方法实现一个完整的功能,如果用继承的方式来实现,势必需要大量的不确定的定义类。因此可以采用装修者的模式在运行阶段动态的定义类。
使用范围
- 动态地扩充子类的功能
- 组合使用多个子类的功能
使用方法
通过建立一个Decorator类来包裹一个原始类,同时将这个原始类作为参数来传递给Decorator的实现子类来间接引用原始类的所有方法,同时实现子类可以扩充其他功能,这样一层套一层,就能动态实现类功能的组合,就好像装修一样。
举例说明
创建一个Windows风格的窗口,使用一个Draw的方法来完成窗口的绘制。首先定义一个接口Windows,期望它的实现类能完成接口定义的所有功能。
public interface Windows { public void draw(); public String getDescription(); }
现在创建一个普通的窗口,比如画出矩形形状,绘出里面的菜单等等。
public class CommonWindows implements Windows{ public void draw(){ // draw menus } public String getDescription(){ return "Common Windows"; } }
此刻,如果需要该窗口能含有水平滚动条,该如何做呢?最简单的方法是创建一个实现类来实现接口完成。都可以。同样道理,如果需要创建含有垂直滚动条的 窗口,那就定义一个类似的实现类来完成接口的定义。问题:如果需要创建一个既有水平滚动条又有水平滚动条,同时又是普通窗口(当然有复杂窗口)的window,该如何做呢?显然再定义一个类就不合适了。Decorator就派到了用场。
public abstract class WindowsDecorator implements Windows{ public Windows decoratedWindows; public WindowsDecorator(Windows winToBeDecorated){ decoratedWindows = winToBeDecorated; } }
注意Windows在此处是作为参数被构造器包裹起来的,其作用就是要实现层层包裹,完成功能的装修。
然后开始定义水平滚动条的窗口,注意它不直接绘制菜单(交给被包裹的类去做),只负责自己的任务,既,画水平滚动条。
public class HorizontalBarWindows extends WindowsDecorator{ public HorizontalBarWindows(Windows winToBeDecorated) { super(winToBeDecorated); } public void draw(){ drawHorizontalBar(); decoratedWindows.draw(); } public void drawHorizontalBar(){ // draw horizontal bar codes here } public String getDescription(){ return decoratedWindows.getDescription() + " + Horizontal Bar"; } }
再定义一个垂直的:
public class VerticalBarWindows extends WindowsDecorator{ public VerticalBarWindows(Windows winToBeDecorated) { super(winToBeDecorated); } public void draw(){ drawHorizontalBar(); decoratedWindows.draw(); } public void drawHorizontalBar(){ // draw horizontal bar codes here } public String getDescription(){ return decoratedWindows.getDescription() + " + Vertical Bar"; } }
Windows该有的功能都有了,接下来就看客户端是如何动态的去装修。 定义一个含水平滚动条的普通窗口:
public class Client { public static void main(String args[]){ Windows win = new HorizontalBarWindows(new CommonWindows()); System.out.println(win.getDescription()); } }
定义一个含垂直滚动条的普通窗口:
public class Client { public static void main(String args[]){ Windows win = new VerticalBarWindows(new CommonWindows()); System.out.println(win.getDescription()); } }
定义一个含水平和垂直滚动条都包括的普通窗口:
public class Client { public static void main(String args[]){ Windows win = new HorizontalBarWindows(new VerticalBarWindows(new CommonWindows())); System.out.println(win.getDescription()); } }
类结构示意
该样例的类结构如下:
注意WindowsDecorator对Windows的引用是通过自身的构造参数decoratedWindows来实现的。