JAVA設計模式之-裝飾者模式

定義

裝飾者模式:在不改變原類文件以及不使用繼承的情況下,動態地將責任附加到對象上,從而實現動態拓展一個對象的功能。它是通過創建一個包裝對象,也就是裝飾來包裹真實的對象。

設計原則

開放-關閉原則:類應該對拓展開放,對修改關閉

類圖

這裏寫圖片描述

1、Component是基類。通常是一個抽象類或者一個接口,定義了屬性或者方法,方法的實現可以由子類實現或者自己實現。通常不會直接使用該類,而是通過繼承該類來實現特定的功能,它約束了整個繼承樹的行爲。比如說,如果Component代表人,即使通過裝飾也不會使人變成別的動物。
2、ConcreteComponent是Component的子類,實現了相應的方法,它充當了“被裝飾者”的角色。
3、Decorator也是Component的子類,它是裝飾者共同實現的抽象類(也可以是接口)。比如說,Decorator代表衣服這一類裝飾者,那麼它的子類應該是T恤、裙子這樣的具體的裝飾者。
4、ConcreteDecorator是Decorator的子類,是具體的裝飾者,由於它同時也是Component的子類,因此它能方便地拓展Component的狀態(比如添加新的方法)。每個裝飾者都應該有一個實例變量用以保存某個Component的引用,這也是利用了組合的特性。在持有Component的引用後,由於其自身也是Component的子類,那麼,相當於ConcreteDecorator包裹了Component,不但有Component的特性,同時自身也可以有別的特性,也就是所謂的裝飾。

實例

下面就以一個經典案例星巴克咖啡說明:

Step 1、創建Component基類

public abstract class Beverage {
    protected String description = "Unknown Beverage";

    public String getDescription() {
        return description;
    }

    public abstract double cost();
}

Step 2、創建被裝飾者——ConcreteComponent

public class DarkRoast extends Beverage {
    public DarkRoast() {
        description = "Dark Roast Coffee";
    }

    @Override
    public double cost() {
        return .99;
    }
}
public class Espresso extends Beverage {

    public Espresso() {
        description = "Espresso";
    }

    @Override
    public double cost() {
        return 1.99;
    }
}
public class HouseBlend extends Beverage {
    public HouseBlend() {
        description = "House Blend Coffee";
    }

    @Override
    public double cost() {
        return .89;
    }
}
public class LowCaffeine extends Beverage {
    public LowCaffeine() {
        description = "Low Caffeine Coffee";
    }

    @Override
    public double cost() {
        return 1.05;
    }
}

Step 3、創建裝飾者基類-Decorator

public abstract class CondimentDecorator extends Beverage {
    public abstract String getDescription();
}

Step 4、創建具體裝飾者-ConcreteDecorator

public class Milk extends CondimentDecorator {
    Beverage beverage;

    public Milk(Beverage beverage) {
        this.beverage = beverage;
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + ",Milk";
    }

    @Override
    public double cost() {
        return beverage.cost() + .10;
    }
}
public class Mocha extends CondimentDecorator {
    Beverage beverage;

    public Mocha(Beverage beverage) {
        this.beverage = beverage;
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + ",Mocha";
    }

    @Override
    public double cost() {
        return beverage.cost() + .20;
    }
}
public class Soy extends CondimentDecorator {
    Beverage beverage;

    public Soy(Beverage beverage) {
        this.beverage = beverage;
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + ",Soy";
    }

    @Override
    public double cost() {
        return beverage.cost() + .15;
    }
}
public class Whip extends CondimentDecorator {
    Beverage beverage;

    public Whip(Beverage beverage) {
        this.beverage = beverage;
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + ",Whip";
    }

    @Override
    public double cost() {
        return beverage.cost() + .10;
    }
}

step5:使用

    Beverage beverage = new HouseBlend();
    beverage = new Soy(beverage);
    beverage = new Mocha(beverage);
    beverage = new Whip(beverage);
    Log.e("Test",beverage.getDescription() + " ¥" + beverage.cost());

邏輯圖:

這裏寫圖片描述

特點

以上就是裝飾者模式的一個小栗子,講述了裝飾者的基本用法。通過上述的例子,我們可以總結一下裝飾者模式的特點。
(1)裝飾者和被裝飾者有相同的接口(或有相同的父類)。
(2)裝飾者保存了一個被裝飾者的引用。
(3)裝飾者接受所有客戶端的請求,並且這些請求最終都會返回給被裝飾者(參見韋恩圖)。
(4)在運行時動態地爲對象添加屬性,不必改變對象的結構。

使用裝飾者模式的最大好處就是其拓展性十分良好,通過使用不同的裝飾類來使得對象具有多種多樣的屬性,靈活性比直接繼承好。然而它也有缺點,那就是會出現很多小類,即裝飾類,使程序變得複雜。

應用

學習了裝飾者模式用法、特點以及優缺點後,我們再來看看裝飾者模式在實際開發過程的應用。裝飾者模式在Java中經常出現的地方就是JavaIO。提到JavaIO,腦海中就冒出了大量的類:InputStream、FileInputStream、BufferedInputStream……等,真是頭都大了,其實,這裏面大部分都是裝飾類,只要弄清楚這一點就容易理解了。我們來看看JavaIO是怎樣使用裝飾者模式的。
從字符流來分析,我們知道,有兩個基類,分別是InputStream和OutputStream,它們也就是我們上面所述的Component基類。接着,它有如下子類:FileInputStream、StringBufferInputStream等,它們就代表了上面所述的ConcreteComponent,即裝飾對象。此外,InputStream還有FilterInputStream這個子類,它就是一個抽象裝飾者,即Decorator,那麼它的子類:BufferedInputStream、DataInputStream等就是具體的裝飾者了。那麼,從裝飾者模式的角度來看JavaIO,是不是更加容易理解了呢?

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