1. 程式人生 > >一天一個設計模式---裝飾者模式

一天一個設計模式---裝飾者模式

優點:它可以動態為物件新增功能。

場景:我們希望為某個物件而不是整個類新增一些功能。

一、角色及作用

裝飾者和被裝飾者擁有相同的元件介面。被裝飾者是系統的核心元件,完成特定功能。裝飾者則可以在被裝飾者的方法前後,加上特定的前置處理和後置處理,增強被裝飾者的功能(怎麼和代理模式好像!_!,一臉懵逼)

角色 作用
元件介面 為裝飾者和被裝飾者的超類或介面。定義被裝飾者的核心功能,以及裝飾者需要加強的功能
具體元件(被裝飾者) 實現元件介面的的核心方法,完成具體業務邏輯
裝飾者 實現元件介面,持有一個被裝飾物件
具體裝飾者 具體實現裝飾的業務邏輯。各個具體裝飾者是可以相互疊加的

二、裝飾者模式

場景:奶茶哥哥的奶茶店開張了,我們推出了兩種產品—奶茶和茶葉茶。我們的飲料需要實現自己的描述和自己的價格。

// 飲料的基類(元件介面)
public interface Beverage {

    public String getDescription();

    public double cost();
}
// 奶茶(被裝飾者)
public class Milk implements Beverage {

    @Override
    public double cost() {
        return .56;
    }

    @Override
public String getDescription() { return "Milk"; } }
// 茶葉茶(被裝飾者)
public class Tea implements Beverage {

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

    @Override
    public String getDescription() {
        return "Tea";
    }

}

奶茶店開張後,我們的飲料很暢銷,但是沒有新的產品是無法滿足客戶的。於是,我們研製了調料,讓我們的飲料喝起來味道更好。

// 調料的基類(裝飾者)
public abstract class CondimentDecorator implements Beverage {
    Beverage beverage;

    public CondimentDecorator(Beverage beberage) {
        this.beverage = beberage;
    }

}
// 抹茶粉(具體裝飾者)
public class Matcha extends CondimentDecorator {

    public Matcha(Beverage beberage) {
        super(beberage);
    }

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

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

}
// 珍珠(具體裝飾者)
public class Pearl extends CondimentDecorator {

    public Pearl(Beverage beberage) {
        super(beberage);
    }

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

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

}

現在我們提供奶茶的方法如下:

    public static void main(String[] args) {
        Beverage be = new Tea();
        System.out.println(be.getDescription() + "---" + be.cost());
        Beverage b2 = new Pearl(new Milk());
        System.out.println(b2.getDescription() + "---" + b2.cost());
        b2 = new Matcha(b2);
        System.out.println(b2.getDescription() + "---" + b2.cost());
    }

輸出如下:

Tea---1.44
Milk,Pearl---0.76
Milk,Pearl,Matcha---1.26

可見,我們根據所需要的飲料和調料,奶茶哥哥就提供對應的飲料和價格資料。

三、裝飾者模式和代理模式的區別

首先,這兩個模式真心在實現上太像了,都是對業務處理的前後增加前置後置的實現。網上找了很多人對這兩者的理解,這裡總結下我的看法。

裝飾模式:
- 以對客戶端透明的方式擴充套件物件的功能
- 可以說是繼承關係的一個替代方案
- 使用者更關心裝飾後的功能

比如上面的奶茶,使用者希望得到的是—奶茶+珍珠+抹茶,以及他們的總價

代理模式:
- 代理模式對代理的物件施加控制,並不提供物件本身的增強功能
- 使用者通過代理來訪問目標的功能,使用者關心的是原始功能都有什麼功能,而對於代理的時候的處理卻不知道

比如在代理模式中提到的成龍大哥和經紀人的例子,我們更加關心的應該是成龍大哥演戲,而不是經紀人對業務的處理。