Java設計模式の裝飾者模式

來源:互聯網
上載者:User

標籤:ext   turn   新功能   描述   特定   抽象類別   htm   ted   style   

目錄

  

  一、問題引入
  二、設計原則
  三、用裝飾者模式解決問題
  四、裝飾者模式的特點
  五、裝飾者模式的定義
  六、裝飾者模式的實現
  七、java.io包內的裝飾者模式

 

 

 一、問題引入

  咖啡店的類設計:

  一個飲料基類,各種飲料類繼承這個基類,並且計算各自的價錢。

  飲料中需要加入各種調料,考慮在基類中加入一些布爾值變數代表是否加入各種調料,基類的cost()中的計算各種調料的價錢,子類覆蓋cost(),並且在其中調用超類的cost(),加上特定飲料的價錢,計算出子類特定飲料的價錢。

  缺點:類數量爆炸、基類加入的新功能並不適用於所有的子類、調料價錢的改變、新調料的出現都會要求改變現有代碼;有的子類並不適合某些調料等情況……

 二、設計原則

  類應該對擴充開放,對修改關閉。

  我們的目標是允許類容易擴充,在不修改現有代碼的情況下,就可搭配新的行為。

  如能實現這樣的目標,有什麼好處呢?這樣的設計具有彈性可以應對改變,可以接受新的功能來應對改變的需求。

  要讓OO設計同時具備開放性和關閉性,不是一件容易的事,通常來說,沒有必要把設計的每個部分都這麼設計。

  遵循開放-關閉原則,通常會引入新的抽象層次,增加代碼的複雜度。

  我們需要把注意力集中在設計中最有可能改變的地方,然後應用開放-關閉原則。

 三、用裝飾者模式解決問題

  解決咖啡店飲料問題的方法:

  以飲料為主體,然後在運行時以調料來“裝飾”飲料。

  比如,顧客想要摩卡(Mocha)和奶泡(Whip)深焙咖啡(DarkRoast):

  DarkRoast繼承自Beverage,有一個cost()方法。

  第一步,以DarkRoast對象開始;

  第二步,顧客想要摩卡,所以建立一個Mocha裝飾者對象,並用它將DarkRoast對象封裝(wrap)起來;

  第三步,顧客想要奶泡,所以建立一個Whip裝飾者對象,並用它將Mocha對象包起來;(Mocha和Whip也繼承自Beverage,有一個cost()方法);

  最後,為顧客算錢,通過調用最外圈裝飾者(Whip)的cost()就可以。Whip()的cost()會先委託它裝飾的對象(Mocha)計算出價錢,然後在加上奶泡的價錢。Mocha的cost()也是類似。

 四、裝飾者模式的特點

  裝飾者和被裝飾對象有相同的超類型。

  可以用一個或多個裝飾者封裝一個對象。

  因為裝飾者和被裝飾者具有相同的類型,所以任何需要原始對象的場合,可以用裝飾過的對象代替。

  裝飾者可以在所委託被裝飾者的行為之前與/或之後,加上自己的行為,以達到特定的目的。

  對象可以在任何時候被裝飾,所以可以在運行時動態地、不限量地用你喜歡的裝飾者來裝飾對象。

 五、裝飾者模式的定義

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

 六、裝飾者模式的實現

  實作類別圖如下:

裝飾者和被裝飾者具有共同的超類,利用繼承達到“類型匹配”,而不是利用繼承獲得“行為”;將裝飾者和被裝飾者組合時,加入新的行為。

詳細源碼:

package com.blankjor.decorator;/** * @desc 抽象飲料類(抽象組件) * @author Blankjor * @date 2017年5月14日 上午11:14:06 */public abstract class Beverage {    String description = "Unkown Beverage";    public String getDescription() {        return description;    }    /**     * 抽象價格計算方法     *      * @return     */    public abstract double cost();}package com.blankjor.decorator;/** * @desc 濃縮飲料 (具體組件) * @author Blankjor * @date 2017年5月14日 上午11:20:11 */public class Espresso extends Beverage {    public Espresso() {        description = "Espresso";    }    @Override    public double cost() {        return 1.99;    }}package com.blankjor.decorator;/** * @desc House Blend 飲料(具體組件) * @author Blankjor * @date 2017年5月14日 上午11:20:11 */public class HouseBlend extends Beverage {    public HouseBlend() {        description = "House Blend";    }    @Override    public double cost() {        return .20;    }}package com.blankjor.decorator;/** * @desc 抽象裝飾者類 * @author Blankjor * @date 2017年5月14日 上午11:17:12 */public abstract class CondimentDecorator extends Beverage {    /**     * 為了後面的調料都能夠擷取到自己調料的描述     */    public abstract String getDescription();}package com.blankjor.decorator;/** * @desc Mocha調料(具體裝飾者) * @author Blankjor * @date 2017年5月14日 上午11:23:36 */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 .20 + beverage.cost();    }}package com.blankjor.decorator;/** * @desc Soy調料(具體裝飾者) * @author Blankjor * @date 2017年5月14日 上午11:20:11 */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 .60 + beverage.cost();    }}package com.blankjor.decorator;/** * @desc Whip調料(具體裝飾者) * @author Blankjor * @date 2017年5月14日 上午11:20:11 */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 .40 + beverage.cost();    }}package com.blankjor.decorator;/** * @desc 測試裝飾者模式 * @author Blankjor * @date 2017年5月14日 上午11:29:50 */public class MainTest {    public static void main(String[] args) {        // 建立一種調料        Beverage beverage = new Espresso();        // 描述和價格        System.out.println(beverage.getDescription() + " $" + beverage.cost());        Beverage beverage1 = new HouseBlend();        beverage1 = new Mocha(beverage1);        beverage1 = new Whip(beverage1);        beverage1 = new Soy(beverage1);        System.out.println(beverage1.getDescription() + " $" + beverage1.cost());        Beverage beverage2 = new Espresso();        beverage2 = new Mocha(beverage2);        beverage2 = new Whip(beverage2);        beverage2 = new Soy(beverage2);        beverage2 = new Mocha(beverage2);        System.out.println(beverage2.getDescription() + " $" + beverage2.cost());    }}

運行結果:

裝飾者和被裝飾者具有共同的超類,利用繼承達到“類型匹配”,而不是利用繼承獲得“行為”;將裝飾者和被裝飾者組合時,加入新的行為。

  解決本文中飲料的具體問題時,圖中Component即為Beverage(可以是抽象類別或者介面),而ConcreteComponent為各種飲料,Decorator(抽象裝飾者)為調料的抽象類別或介面,ConcreteDecoratorX則為各種具體的調料。

  因為使用對象組合,可以把飲料和調料更有彈性地加以混合與匹配。

  代碼外部細節:

  代碼中實現的時候,通過建構函式將被裝飾者傳入裝飾者中即可,如最後的調用形式如下:

    Beverage beverage = new DarkRoast();

    beverage = new Mocha(beverage);

    beverage = new Whip(beverage);

  即完成了兩層封裝,此時再調用beverage的cost()函數即可得到總價。

七、java.io包內的裝飾者模式

裝飾者模式的缺點:在設計中加入大量的小類,如果過度使用,會讓程式變得複雜。

 

參考:http://www.cnblogs.com/mengdd/archive/2013/01/03/2843439.html

 

Java設計模式の裝飾者模式

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.