裝飾者模式

裝飾者模式

裝飾模式指的是在不必改變原類文件和使用繼承的情況下,動態地擴展一個對象的功能。它是通過創建一個包裝對象,也就是裝飾來包裹真實的對象。

首先來分析一下爲什麼使用裝飾者模式。例如,讓一個對象添加一個新的功能,我們第一想到的就是創建一個類來繼承這個類,然後添加新的功能方法。這種方式在大部分簡單的場景中是可取的,可是也有一些複雜的情況。例如,各種功能之間要相互組合使用,拿手抓餅來說吧,一個手抓餅裏面可以加各種食材,比如加個烤腸,加個雞蛋等等,我以前上班的時候路過地鐵站都會買一個手抓餅當早餐,既美味,又方便。平時的時候我加一個雞蛋,一份青菜,當我發工資的時候我就闊綽一把,加一個雞蛋,一份青菜,再加一個烤腸。可見手抓餅裏的東西是可以隨意組合的,假如說我們用繼承的方式,我想加一個雞蛋和一份青菜,那麼我就要創建一個子類來繼承手抓餅,在子類中組合雞蛋和青菜。如果我想加一個雞蛋一份青菜和一根烤腸,那麼我就要再創建一個子類來繼承手抓餅,在子類中組合雞蛋青菜和烤腸。當然,可能月底了,沒錢了,我只加一個雞蛋,那麼就又多了一種組合方式,可見,這種組合方式是特別多的,如果使用繼承,那麼子類將會多到爆炸。過些時候老闆又推出了新的食品,可以加裏脊肉了,那麼多一種食品,它們的組合方式將會成幾何的方式增長,顯然這種場景下,使用繼承的方式是不可取的,那麼這個時候就可以使用裝飾者模式了。

裝飾模式的使用場景:

1. 需要擴展一個類的功能,或給一個類添加附加職責。
2. 需要動態的給一個對象添加功能,這些功能可以再動態的撤銷。
3. 需要增加由一些基本功能的排列組合而產生的非常大量的功能,從而使繼承關係變的不現實。
4. 當不能採用生成子類的方法進行擴充時。一種情況是,可能有大量獨立的擴展,爲支持每一種組合將產生大量的子類,使得子類數目呈爆炸性增長。另一種情況可能是因爲類定義被隱藏,或類定義不能用於生成子類。

裝飾模式的優點:

1. 符合設計模式中的多用組合,少用繼承和開閉原則
2. 通過使用不同的具體裝飾類以及這些裝飾類的排列組合,設計師可以創造出很多不同行爲的組合。

示例代碼:

抽象手抓餅接口:

/**
 * 手抓餅抽象
 */
public interface HandPancake {
    String description(); //描述
    float price();       //價格
}

創建手抓餅實例:

public class Pancake implements HandPancake{
    private String description="煎餅";
    private float price =4;
    @Override
    public String description() {
        return description;
    }

    @Override
    public float price() {
        return price;
    }
}

抽象手抓餅組合的食材基類:

public abstract class Decorator implements HandPancake{
    protected HandPancake handPancake;
    public Decorator(HandPancake handPancake){
        this.handPancake=handPancake;
    }
}

創建雞蛋食材實例:

public class Egg extends Decorator {
    private String description="雞蛋";
    private float price =1;
    public Egg(HandPancake handPancake){
        super(handPancake);
    }
    @Override
    public String description() {
        return  handPancake.description()+"+"+description;
    }

    @Override
    public float price() {
        return handPancake.price()+price;
    }
}

創建青菜食材實例:

public class Greens extends Decorator {

    private String description="青菜";
    private float price =0.5f;
    public Greens(HandPancake handPancake) {
        super(handPancake);
    }

    @Override
    public String description() {
        return handPancake.description() + "+" + description;
    }

    @Override
    public float price() {
        return handPancake.price() + price;
    }
}

創建熱狗食材實例:

public class HotDog extends Decorator {
    private String description="熱狗";
    private float price =2;
    public HotDog(HandPancake handPancake) {
        super(handPancake);
    }

    @Override
    public String description() {
        return handPancake.description() + "+" + description;
    }

    @Override
    public float price() {
        return handPancake.price() + price;
    }
}

現在可以自由搭配買手抓餅了

/**
 * 手抓餅4元
 * 加雞蛋1元
 * 加熱狗2元
 * 加青菜0.5元
 * 上海手抓餅好貴啊,現在我都不吃了
 */
public class Test {
    public static void main(String[] args) {
        HandPancake pancake = new Pancake();    //一份手抓餅
        pancake = new Egg(pancake);             //加個雞蛋
        pancake = new Greens(pancake);          //加點青菜
        System.out.println("你買的是:" + pancake.description() + "\t總計:" + pancake.price() + "元");
        pancake = new HotDog(pancake);          //再加根烤腸吧
        System.out.println("你買的是:" + pancake.description() + "\t總計:" + pancake.price() + "元");
    }
}

運行結果:


可以看到,使用裝飾者模式,各個食材之間可以隨意組合,並沒有出現類的爆炸性增長。在java中,裝飾者模式使用最經典的就是IO流了,大家可以去操作一下IO流,體會一下裝飾者模式的特點。

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