天天看點

裝飾模式(Decorator Pattern、Wrapper Pattern,對象結構型模式)意圖适用性結構參與者代碼協作效果實作經典例子相關模式

意圖

動态地給一個對象添加一些額外的職責。就增加功能來說,Decorator模式相比生成子類更加靈活。

對裝飾和内容一視同仁。

Decorator是“進行Decorate(裝飾)的主體”的意思。

适用性

當需要給一個類添加新的行為的時候,但基于開閉原則,就使用裝飾模式。

在以下情況使用Decorator模式:

1. 在不影響其他對象的情況下,以動态、透明的方式給單個對象添加職責

2. 處理那些可以撤銷的職責

3. 當不能采用生成之類的方法進行擴充時。一種情況是,可能有大量獨立的擴充,為支援每一種組合将産生大量的子類,使得子類數目呈爆炸性增長。另一種情況可能是因為類定義被隐藏,或者類定義不能生成之類。

結構

裝飾模式(Decorator Pattern、Wrapper Pattern,對象結構型模式)意圖适用性結構參與者代碼協作效果實作經典例子相關模式

參與者

Component

定義一個對象接口,可以給這些對象動态增加職責。

ConcreteComponent

定義一個對象,可以給這個對象增加一些職責

Decorator

維持一個指向Component對象的指針,并定義一個與Component接口一緻的接口(可以直接實作Component接口)。

ConcreteDecorator

向元件添加職責

Client

使用組合完成功能的擴充。

代碼

Component

public interface Component {
    public void defaultMethod();
}
           

ConcreteComponent

public class ConcreteComponent implements Component{
    public void defaultMethod(){
        System.out.println("====ConcreteComponent===defaultMethod===");
    }
}
           

Decorator

public abstract class Decorator implements Component{
    private Component component;
    public Decorator(Component component){
        this.component = component;
    }
    public Component getComponent() {
        return component;
    }
    public void setComponent(Component component) {
        this.component = component;
    }
}
           

ConcreteDecorator

public class ConcreteDecorator1 extends Decorator{

    private int state = 0;

    public ConcreteDecorator1(Component component,int state) {
        super(component);
        this.state = state;
    }

    public void defaultMethod() {
        this.getComponent().defaultMethod();
    }

    public void add1(){
        System.out.println("====ConcreteDecorator1===add1==="+state);
    }

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
    }
}
public class ConcreteDecorator2 extends Decorator{
    public ConcreteDecorator2(Component component) {
        super(component);
    }
    public void defaultMethod() {
        this.getComponent().defaultMethod();
    }
    public void add1(){
        System.out.println("====ConcreteDecorator2===add1===");
    }
    public void add2(){
        System.out.println("====ConcreteDecorator2===add2===");
    }
}
           

Client

public class Client {
    public static void main(String[] args) {
        Component concreteComponent = new ConcreteComponent();
        concreteComponent.defaultMethod();
        System.out.println("=========");
        ConcreteDecorator1 concreteDecorator1 = new ConcreteDecorator1(concreteComponent,1);
        concreteDecorator1.defaultMethod();
        concreteDecorator1.add1();
        System.out.println("=========");
        ConcreteDecorator2 concreteDecorator2 = new ConcreteDecorator2(concreteComponent);
        concreteDecorator2.defaultMethod();
        concreteDecorator2.add1();
        concreteDecorator2.add2();
        System.out.println("=========");
        ConcreteDecorator1 concreteDecorator3 = new ConcreteDecorator1(concreteDecorator2,1);
        concreteDecorator3.defaultMethod();
        concreteDecorator3.add1();
        System.out.println("=========");

        ConcreteDecorator2 concreteDecorator4 = new ConcreteDecorator2(concreteDecorator1);
        concreteDecorator4.defaultMethod();
        concreteDecorator4.add1();
        concreteDecorator4.add2();
    }
}
           

協作

Decorator将請求轉發給它的Component對象,并有可能在轉發請求前後執行一些附加的動作。

效果

比靜态內建更加靈活

與對象的靜态繼承相比,Decorator模式提供了更加靈活的向對象添加職責的方式。可以用添加和分離的方法,用裝飾在運作時刻增加或删除職責。相比之下,繼承機制要求為每個添加的職責建立一個新的子類。這會産生許多新類,并且會增加系統的複雜度。此外,為一個特定的Component類提供多個不同的Decorator類,這就使得你可以對一些職責進行混合和比對。

使用Decorator模式可以容易地重複添加一個特性。

避免在層次結構高層的類有太多的特征

Decorator模式提供了一種“即用即付”的方法來添加職責。它并不試圖在一個複雜的可定制的類中支援所有可預見的特征。相反,你可以定義一個簡單的類,并且用Decorator類給他逐漸地添加功能。可以從簡單的部件組合出複雜的功能。這樣,應用程式不必為不需要的特征付出代價。同時也更容易不依賴于Decorator所擴充(甚至是不可預知的擴充)的類而獨立定義新類型的Decorator。擴充一個複雜類的時候,很可能會暴漏與添加的職責無關的細節。

Decorator與它的Component不一樣

Decorator是一個透明的包裝。如果我們從對象辨別的觀點出發,一個被裝飾了的元件與這個元件是有差别的,是以使用裝飾時不應該依賴于對象辨別。

有許多小對象

采用Decorator模式進行系統設計往往會産生許多看上去類似的小對象,這些對象僅僅在他們互相連接配接的方式上有所不同,而不是他們的類或是他們的屬性值有所不同。盡管對于那些了解這些系統的人來說,很容易對它們進行定制,但是很難學習這些系統,排錯也很困難。

實作

使用Decorator模式時應該注意以下幾點:

接口一緻性

裝飾對象的接口必須和它所裝飾的Component的接口是一緻的,是以,所有的ConcreteDecorator類必須有一個公共的父類。

省略抽象的Decorator類

當你僅需要添加一個職責時,沒有必要定義抽象Decorator類。你嘗嘗需要處理現存的類層次結構而不是設計一個新系統,這時你可以把Decorator向Component轉發請求的職責合并到ConcreteDecorator中。

保持Component類的簡單性

為了保證接口的一緻性,元件和裝飾必須有一個公共的Component父類。是以保持這個類的簡單性是很重要的:即,它應集中于定義接口而不是存儲資料。對資料表示的定義應該延遲到子類中,否則Component類會變得過于複雜和龐大,因而難以大量使用。賦予Component太多的功能也使得,具體的子類有一些它們并不需要的功能的可能性大大增加。

改變對象外殼與改變對象核心

我們可以将Decorator看作一個對象的外殼,它可以改變這個對象的行為。另外一種方法是改變對象的核心(Strategy模式)。

當Component類原本就很龐大時,使用Decorator模式代價太高,Strategy模式相對更好一些。在Strategy模式中,元件将它的一些行為轉發給一個獨立的政策對象,我們可以替換strategy對象,進而改變或擴充元件的功能。

由于Decorator模式僅從外部改變元件,是以元件無需對它的裝飾有任何了解:也就是說這些裝飾對元件是透明的。

在Strategy模式中,component元件本身知道可能進行哪些擴充,是以它必須引用并維護相應的政策。

基于Strategy的方法可能需要修改component元件以适應新的擴充。另一方面,一個政策可以有自己特定的接口,而裝飾的接口則必須與元件的接口一緻。這意味着即使Component類很龐大,政策也可以很小。

經典例子

裝飾模式(Decorator Pattern、Wrapper Pattern,對象結構型模式)意圖适用性結構參與者代碼協作效果實作經典例子相關模式

相關模式

Adapter Pattern

Decorator模式不同于Adapter模式,因為裝飾僅改變對象的職責而不改變它的接口;而擴充卡講給對象一個全新的接口。

Decorator Pattern 不改變内容的接口(API)就能建立外框(穿透作用)。

Composite Pattern

可以将裝飾視為一個退化的,僅有一個元件的組合。然而,裝飾僅給對象添加一些額外的職責,它的目的不在于對象聚集。

側重通過遞歸組合構造類,使不同的對象、多重的對象可以“一視同仁”;而裝飾模式僅僅是借遞歸組合來達到定義的目的

Strategy Pattern

用一個裝飾你可以改變對象的外表;而Strategy模式使得你可以改變對象的核心。

Decorator Pattern 可利用更換外框或增加其他外框的方式增加新功能;Strategy Pattern:以切換預算法則的方式變換功能。

敬請期待“組合模式(Composite Pattern,對象結構型模式)”