裝飾者模式

裝飾者模式

標籤 : Java與設計模式


裝飾者模式(Decorator): 又稱包裝器(Wrapper), 可以動態地爲一個對象添加一些額外的職責. 就增加功能來說, 裝飾者模式是一種用於替代繼承的技術, 他無須通過增加子類繼承就能擴展對象的已有功能, 而是使用對象的關聯關係代替繼承關係 , 更加靈活, 同時還可避免類型體系的快速膨脹.

  • 模式組件:
組件 描述 I/O示例
Component 抽象構件角色, 真實對象和裝飾對象的共有接口. 這樣,客戶端就能以調用真實對象的相同方式裝飾對象交互. InputStream/OutputStream
ConcreteComponent 具體構件角色,真實對象 FileInputStream/FileOutputStream
Decorator 裝飾抽象類, 實現了Component, 並持有一個Component引用, 接受所有客戶端請求,並將請求轉發給真實對象, 這樣,就能在真實對象調用的前後增強新功能. 但對於Component來說, 是無需知道Decorator存在的. FilterInputStream/FilterOutputStream
ConcreteDecorator 具體裝飾角色,完成對Component的具體增強. BufferedInputStream/BufferedOutputStream

是你還有你, 一切拜託你.(圖片來源: 《JAVA與模式》之裝飾模式)


實現

  • Component
/**
 * @author jifang
 * @since 16/8/20 下午5:55.
 */
public interface Component {

    void operator();
}

class ConcreteComponent implements Component {

    @Override
    public void operator() {
        System.out.println("具體對象" + this.toString() + "的操作");
    }
}
  • Decorator
public abstract class Decorator implements Component {

    protected Component component;

    public Decorator(Component component) {
        this.component = component;
    }

    @Override
    public abstract void operator();
}

class BeforeAdviceDecorator extends Decorator {

    public BeforeAdviceDecorator(Component component) {
        super(component);
    }

    @Override
    public void operator() {
        System.out.println(" -> 前置增強");
        this.component.operator();
    }
}

class AfterAdviceDecorator extends Decorator {

    public AfterAdviceDecorator(Component component) {
        super(component);
    }

    @Override
    public void operator() {
        this.component.operator();

        System.out.println("後置增強 -> ");
    }
}
  • Client
public class Client {

    @Test
    public void client() {

        // 裸Component
        Component component = new ConcreteComponent();
        component.operator();


        // 前置增強
        component = new BeforeAdviceDecorator(component);
        component.operator();

        // + 後置增強
        component = new AfterAdviceDecorator(component);
        component.operator();
    }
}

注: 如果只有ConcreteComponent而沒有抽象的Component, 那麼Decorator可直接繼承ConcreteComponent. 同樣, 如果只有一個ConcreteDecorator, 那就沒有必要建立一個獨立的Decorator, 將DecoratorConcreteDecorator的職責合併.


小結

  • 裝飾者模式是爲已有功能動態添加更多功能的一種方式: 把類內裝飾邏輯從類中剝離, 以簡化原有類設計:
    • 有效地將類的核心職責和裝飾功能區分開;
    • 去除相關類中重複的裝飾邏輯;
    • 可以對一個對象裝飾多次, 構造出不同行爲的組合, 得到功能更強大的對象;
    • 具體構件類和具體裝飾類可獨立變化, 且用戶可根據需要增加新的具體構件子類具體裝飾子類.
  • 與橋接模式的對比
    兩個模式都是爲了解決子類過多問題, 但他們的誘因不同:
    • 橋接模式對象自身有沿着多個維度變化的趨勢, 本身不穩定;
    • 裝飾者模式對象自身非常穩定, 只是爲了增加新功能/增強原功能.
  • 與適配器模式的不同
    裝飾者與適配器都有一個別名:包裝模式(Wrapper), 它們看似都是起到包裝一個接口/類/對象的作用, 但包裝形式卻不同.

    • 適配器的意義是將一個接口轉變成另一個接口: 通過改變接口達到重複使用的目的;
    • 而裝飾者不改變被裝飾對象的接口, 而恰恰保持了原有的接口: 增強原有對象的功能, 或改變原有對象的處理方法而提升性能.
  • 繼承、裝飾者模式、動態代理對比

* 繼承 裝飾者 動態代理
對象 被增強對象不能變 被增強對象可變 被增強對象可變
內容 增強內容不能變 增強內容不可變 增強內容可變
  • 常見場景
    當系統更新、原有邏輯需要增強時, 我們最初的想法是 向舊的類中添加新代碼, 由新代碼裝飾原有類的主要行爲, 他們會在主類中加入新的字段/方法/邏輯, 但同樣也增加了主類的複雜度, 而這些新加入的內容僅僅是爲了滿足一些只在某種特定情況下才會執行的特殊行爲的需要. 而裝飾者模式提供了一個解決該問題的非常好的方案: 把每個要裝飾的功能放在單獨的類中, 並讓這個類包裝它所要裝飾的對象, 當需要執行特殊行爲時, 客戶代碼就可以在運行時根據需要有選擇地、按順序地使用裝飾過的包裝對象了, 如:

參考:
設計模式: 可複用面向對象軟件的基礎
大話設計模式
高淇講設計模式
深入分析Java Web技術內幕(修訂版)
裝飾模式與適配器模式的的區別


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章