装饰模式
概述
23种设计模式之一,英文叫DecoratorPattern,中文也叫装饰模式、修饰模式。装饰模式是在不改变类文件和不使用继承的情况下,运行期动态扩展一个对象的功能。原理是:增加一个修饰类包裹原来的类,包裹的方式一般是通过在将原来的对象作为修饰类的构造函数的参数。装饰类实现新的功能,但是,在不需要用到新功能的地方,它可以直接调用原来的类中的方法。修饰类必须和原来的类有相同的接口(没有接口可以直接继承自原来的类)。修饰模式是类继承的另外一种选择。类继承在编译时候增加行为,而装饰模式是在运行时增加行为。
UML
实现
Component.java,接口。
public interface Component { void operation(); } |
ConcreteComponent.java,原有类实现(需要扩展)。
public class ConcreteComponent implements Component { public void operation() { System.out.println("具体对象的操作"); } } |
Decorator.java,抽象修饰类。
public abstract class Decorator implements Component { protected Componentcomponent; public Decorator(Component component) { this.component = component; } public void operation() { if(component !=null) component.operation(); } } |
ConcreteDecoratorA.java,实际修饰类A。
public class ConcreteDecoratorA extends Decorator { public ConcreteDecoratorA(Component component) { super(component); } @Override public void operation() { super.operation(); System.out.println("对象A扩展的操作"); } } |
ConcreteDecoratorB.java,实际修饰类B。
public class ConcreteDecoratorB extends Decorator { public ConcreteDecoratorB(Component component) { super(component); } @Override public void operation() { super.operation(); System.out.println("对象B扩展的操作"); } } |
DecoratorTest.java,客户端。
public class DecoratorTest { public static void main(String[] args) { Component component = new ConcreteDecoratorB( new ConcreteDecoratorA( new ConcreteComponent())); component.operation(); } } |
输出结果:
具体对象的操作 对象A扩展的操作 对象B扩展的操作 |
上面客户端的调用方式是不是和如下的代码有些类似,没错,Java中的I/O类库使用的就是装饰模式。
BufferedInputStream bis = new BufferedInputStream( new FileInputStream("")); |
上面就是装饰模式的模型,如果有不明白,可以结合代码、UML、定义一起看一下。
实例
需求
一个窗口系统中的窗口,允许这个窗口内容滚动,我们希望给它添加水平或垂直滚动条(*)。
实现
Window.java,窗口接口。
public interface Window { public void draw(); public String getDescription(); } |
SimpleWindow.java,简单窗口,不带任何修饰。
public class SimpleWindow implements Window { public void draw() { // draw window } public String getDescription() { return "simple window"; } } |
WindowDecorator.java,窗口装饰抽象类。
public abstract class WindowDecoratorimplements Window { protected WindowdecoratedWindow;// the Window being decorated public WindowDecorator(Window decoratedWindow) { this.decoratedWindow = decoratedWindow; } } |
HorizontalScrollBarDecorator.java,横向滚动条装饰类。
public class HorizontalScrollBarDecorator extends WindowDecorator { public HorizontalScrollBarDecorator(Window decoratedWindow) { super(decoratedWindow); } public void draw() { drawHorizontalScrollBar(); decoratedWindow.draw(); } private void drawHorizontalScrollBar() { // draw the horizontal scrollbar } public String getDescription() { return decoratedWindow.getDescription() + ", including horizontal scrollbars"; } } |
VerticalScrollBarDecorator.java,纵向滚动条装饰类。
public class VerticalScrollBarDecorator extends WindowDecorator { public VerticalScrollBarDecorator(Window decoratedWindow) { super(decoratedWindow); } public void draw() { drawVerticalScrollBar(); decoratedWindow.draw(); } private void drawVerticalScrollBar() { // draw the vertical scrollbar } public String getDescription() { return decoratedWindow.getDescription() + ", including vertical scrollbars"; } } |
DecoratedWindowTest.java,客户端。
public class DecoratedWindowTest { public static void main(String[] args) { // create a decorated Window with horizontal and vertical scrollbars Window decoratedWindow = new HorizontalScrollBarDecorator( new VerticalScrollBarDecorator( new SimpleWindow())); // print the Window's description System.out.println(decoratedWindow.getDescription()); } } |
输出结果:
simple window, including vertical scrollbars, including horizontal scrollbars |
将不同的装饰区分开来,并且和原有的窗口分开,这样通过包装,我可以创建一个只带横向(纵向)滚动条的窗口,也可以创建不带滚动条的窗口,任意组合。
总结
装饰模式是不使用继承的情况下,可以动态扩展一个类,并且比继承更灵活(上面的实例)。