23種設計模式之一,英文叫DecoratorPattern,中文也叫裝飾模式、修飾模式。裝飾模式是在不改變類檔案和不使用繼承的情況下,運作期動态擴充一個對象的功能。原理是:增加一個修飾類包裹原來的類,包裹的方式一般是通過在将原來的對象作為修飾類的構造函數的參數。裝飾類實作新的功能,但是,在不需要用到新功能的地方,它可以直接調用原來的類中的方法。修飾類必須和原來的類有相同的接口(沒有接口可以直接繼承自原來的類)。修飾模式是類繼承的另外一種選擇。類繼承在編譯時候增加行為,而裝飾模式是在運作時增加行為。

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 Component component; 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 Window decoratedWindow;// 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
将不同的裝飾區分開來,并且和原有的視窗分開,這樣通過包裝,我可以建立一個隻帶橫向(縱向)滾動條的視窗,也可以建立不帶滾動條的視窗,任意組合。
裝飾模式是不使用繼承的情況下,可以動态擴充一個類,并且比繼承更靈活(上面的執行個體)。