什么是修饰模式
修饰模式是面向对象模式的一种,该模式可以动态向类中添加新的功能。动态指的是在程序运行时候,而我们常用的扩展功能的方法是写一个子类继承父类,这样的继承是静态的,因为这样的扩展方法是程序编译时候就体现出来了。

在上图中可以看到,接口类Component有2个实现,ConcreteComponent类和Decorator类,Decorator类和它的2个子类对ConcreatedComponent类做了修饰, 这样的实现方式就是修饰模式。子类ConcreteDectoratorExtendingFunctionality和ConcreteDecoratorExtendingState类在ConcreatedComponent类的基础之上增加了新的功能。
修饰模式存在的作用
之前讨论定义时候说到动态的增加类的功能是修饰模式的作用,而子类增加功能的方式是静态的。子类这样的增加方式并不完美。假设这样的情况,需要给一个类PClass增加特性A,于是我们有了子类APClass, 需要特性B,于是有了BPClass, 需要特性C,有了CPClass, 现在需要特性AB,可以定义子类ABPClass,这已经有了很多的子类了,如果我们还需要把这些特性任意的组合的话,这个子类就更加的复杂了。并且,我们在编译这个子类的时候,实例化了ABPClass, BPClass , PClass这三个类。于是, 功能就像是类的模板的一样,不同的功能不同的模板,极度不方便。
修饰模式解决的就是这样的问题,修饰类在PClass的基础可以直接添加特性A和B, 没有子类BPClass需要被实例化。并且调用PClass的实例也是在代码的运行时,这个就是动态的了。
请看下面的代码。代码源自wikipedia.
//接口,我们想要扩展的就是window类的功能
public interface Window {
public void draw();
public String getDescription();
}
//实现类
public class SimpleWindow implements Window {
@Override
public void draw() {
System.out.println("draw window");
}
@Override
public String getDescription() {
return "Simple Window";
}
}
//window的修饰类,这里使用的修饰方法为将window做参数传入构造方法中,这样的话,修饰类的子类可以动态的增加新的功能,也就是不需要编译时候就实例化window类了。
public abstract class WindowDecorator implements Window {
protected Window decoratedWindow;
public WindowDecorator(Window decoratedWindow){
this.decoratedWindow = decoratedWindow;
}
}
//修饰类的一个子类。为window类增加了新的方法 drawVScrollBar.
public class VScrollBarDecorator extends WindowDecorator {
public VScrollBarDecorator(Window decoratedWindow) {
super(decoratedWindow);
}
//这里可以看到window的功能方便的被扩展了,调用decoratedWindow.draw之前还可以增加其他的功能。并且在使用该方法的时候,才会去实例化window和decoratedWindow
@Override
public void draw() {
drawVScrollBar();
decoratedWindow.draw();
}
private void drawVScrollBar(){
}
@Override
public String getDescription() {
return decoratedWindow.getDescription() + "-- include vscorllbar";
}
}
//另外一个增加了功能那个的类
public class HScrollBarDecorator extends WindowDecorator{
public HScrollBarDecorator(Window decoratedWindow) {
super(decoratedWindow);
}
@Override
public void draw() {
drawHScrollBar();
decoratedWindow.draw();
}
private void drawHScrollBar(){
}
@Override
public String getDescription() {
return decoratedWindow.getDescription() + "--include hscrollbar";
}
}
public class DecoratedWindowTest {
public static void main(String[] args){
//这里可以看到原来见到的SimpleWindow就有了HScrollbar和VScrollBar
Window decoratedWindow = new HScrollBarDecorator(
new VScrollBarDecorator(new SimpleWindow()));
System.out.println(decoratedWindow.getDescription());
}
}
上面的代码中,给SimpleWindow增加2个特性HScrollBar和VScrollBar。若是在用子类的情况下,那么就需要定义至少三个子类。但是在使用修饰模式的情况下, 新的特性只需要在实例化时当作参数传进去就可以了。