裝飾者模式
標籤 : 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, 將Decorator和ConcreteDecorator的職責合併.
小結
- 裝飾者模式是爲已有功能動態添加更多功能的一種方式: 把類內裝飾邏輯從類中剝離, 以簡化原有類設計:
- 有效地將類的核心職責和裝飾功能區分開;
- 去除相關類中重複的裝飾邏輯;
- 可以對一個對象裝飾多次, 構造出不同行爲的組合, 得到功能更強大的對象;
- 具體構件類和具體裝飾類可獨立變化, 且用戶可根據需要增加新的具體構件子類和具體裝飾子類.
- 與橋接模式的對比
兩個模式都是爲了解決子類過多問題, 但他們的誘因不同:
- 橋接模式對象自身有沿着多個維度變化的趨勢, 本身不穩定;
- 裝飾者模式對象自身非常穩定, 只是爲了增加新功能/增強原功能.
與適配器模式的不同
裝飾者與適配器都有一個別名:包裝模式(Wrapper), 它們看似都是起到包裝一個接口/類/對象的作用, 但包裝形式卻不同.- 適配器的意義是將一個接口轉變成另一個接口: 通過改變接口達到重複使用的目的;
- 而裝飾者不改變被裝飾對象的接口, 而恰恰保持了原有的接口: 增強原有對象的功能, 或改變原有對象的處理方法而提升性能.
繼承、裝飾者模式、動態代理對比
* | 繼承 | 裝飾者 | 動態代理 |
---|---|---|---|
對象 | 被增強對象不能變 | 被增強對象可變 | 被增強對象可變 |
內容 | 增強內容不能變 | 增強內容不可變 | 增強內容可變 |
- 常見場景
當系統更新、原有邏輯需要增強時, 我們最初的想法是 向舊的類中添加新代碼, 由新代碼裝飾原有類的主要行爲, 他們會在主類中加入新的字段/方法/邏輯, 但同樣也增加了主類的複雜度, 而這些新加入的內容僅僅是爲了滿足一些只在某種特定情況下才會執行的特殊行爲的需要. 而裝飾者模式提供了一個解決該問題的非常好的方案: 把每個要裝飾的功能放在單獨的類中, 並讓這個類包裝它所要裝飾的對象, 當需要執行特殊行爲時, 客戶代碼就可以在運行時根據需要有選擇地、按順序地使用裝飾過的包裝對象了, 如:
- Java I/O流體系(詳細可參考: Java I/O);
Servlet
API:HttpServletRequestWrapper
/HttpServletResponseWrapper
增強Servlet功能(詳細可參考Servlet - Listener、Filter、Decorator)
- by 攻城師@翡青
- Email: [email protected]
- 博客: 攻城師-翡青 - http://blog.csdn.net/zjf280441589
- 微博: 攻城師-翡青 - http://weibo.com/u/3319050953