天天看點

設計模式學習07----之裝飾者模式

概述

上一篇我們學習了擴充卡模式,今天我們接着學習裝飾模式。

定義和結構

裝飾者模式:動态地将責任附加到對象上,若要擴充功能,裝飾者提供比繼承更有彈性的替代方案

設計模式學習07----之裝飾者模式

裝飾模式的角色有:

1. 抽象元件(Component)角色:給出一個抽象接口,以規範準備接收附加責任的對象。

2. 具體元件(ConcreteComponent)角色:定義一個将要接收附加責任的類

3. 裝飾者(Decorator)角色: 持有一個構件對象的執行個體。并實作一緻的接口。

4. 具體裝飾(Concrete Decorator)角色:負責給構件對象添加上附加的責任。

以咖啡調料品為例

假設有這樣一個場景:張三買了一杯25元的美式咖啡,喝了幾口,太苦了。然後加了2元一份的糖包(sugar),李四買了一杯30元的拿鐵,然後在裡面加了一份5元的牛奶(milk)。這樣一種情況,就屬于裝飾器模式,咖啡作為元件,調料包作為裝飾器。

類圖

設計模式學習07----之裝飾者模式

抽象咖啡類(Coffee)

package com.decorate;

/**
 * 抽象咖啡類
 *
 * @author xiang.wei
 * @create 2018/4/10 19:44
 */
public abstract class Coffee {
    //咖啡資訊
    private String coffeeInfo = "普通咖啡";

    public String getCoffeeInfo() {
        return coffeeInfo;
    }

    public abstract int cost();
}      

具體咖啡類

package com.decorate;

/**
 * 美式咖啡類
 * @author xiang.wei
 * @create 2018/4/11 13:50
 */
public class Americano extends Coffee {
    @Override
    public String getCoffeeInfo() {
        return "美式咖啡";
    }

    @Override
    public int cost() {
        return 25;
    }
}      
package com.decorate;

/**
 * 拿鐵類
 *
 * @author xiang.wei
 * @create 2018/4/11 13:49
 */
public class Latte extends Coffee {
    @Override
    public String getCoffeeInfo() {
        return "拿鐵";
    }

    @Override
    public int cost() {
        return 30;
    }
}      

調料類(Flavour):

package com.decorate;

/**
 * 配料抽象類
 * @author xiang.wei
 * @create 2018/4/11 13:54
 */
public abstract class Flavour extends Coffee {
    @Override
    public abstract String getCoffeeInfo();

}      

調料類(Flavour)繼承了咖啡類(Coffee),并重寫了​

​getCoffeeInfo()​

​​方法。

具體調料類

package com.decorate;

/**
 * 配料牛奶類
 *
 * @author xiang.wei
 * @create 2018/4/11 13:54
 */
public class Milk extends Flavour {
    private Coffee coffee;

    public Milk(Coffee coffee) {
        this.coffee = coffee;
    }

    @Override
    public String getCoffeeInfo() {
        return coffee.getCoffeeInfo()+"加了牛奶";
    }

    @Override
    public int cost() {
        return coffee.cost()+5;
    }
}      
package com.decorate;

/**
 * 配料糖類
 *
 * @author xiang.wei
 * @create 2018/4/11 13:54
 */
public class Sugar extends Flavour {
    private Coffee coffee;

    public Sugar(Coffee coffee) {
        this.coffee = coffee;
    }

    @Override
    public String getCoffeeInfo() {
        return coffee.getCoffeeInfo()+"加了糖";
    }

    @Override
    public int cost() {
        return coffee.cost()+3;
    }
}      

用戶端類:

package com.decorate;

/**
 * @author xiang.wei
 * @create 2018/4/11 14:18
 */
public class Client {
    public static void main(String[] args) {
        Coffee coffee1 = new Americano();
        Coffee coffee2 = new Latte();
        Flavour flavour = new Sugar(coffee1);
        System.out.println(flavour.getCoffeeInfo()+"現在的價格是:"+flavour.cost());
        Flavour flavour1 = new Milk(coffee2);
        System.out.println(flavour1.getCoffeeInfo()+"現在的價格是:"+flavour1.cost());

    }
}      

運作結果是:

美式咖啡加了糖現在的價格是:28
拿鐵加了牛奶現在的價格是:35      

優缺點

  1. 這種比繼承更加靈活機動的特性,也同時意味着更加多的複雜性。
  2. 裝飾模式會導緻設計中出現許多小類,如果過度使用,會使程式變得很複雜。
  3. 裝飾模式是針對抽象元件(Component)類型程式設計。但是,如果你要針對具體元件程式設計時,就應該重新思考你的應用架構,以及裝飾者是否合适。當然也可以改變Component接口,增加新的公開的行為,實作“半透明”的裝飾者模式。在實際項目中要做出最佳選擇。

參考