java常用設計模式(四)裝飾者模式


  設計模式第四篇,裝飾者模式,大家多多指教。

 簡介

  裝飾者模式是動態的將責任附加到對象上(引自《Head First設計模式》)。這里的重點在於動態這兩個字,我們都知道繼承的實現的方式,它是是類編譯的時候就去加載文件,屬於一種靜態的附加,而我們要實現動態的附加就不能單純的通過繼承來實現。在這種背景下,裝飾者模式就應運而生了。裝飾者模式的實現:首先所有的類都有一個共同的抽象,這個抽象可以是一個抽象類,也可以是一個接口,所有的類該抽象的子類或者實現。語言描述比較抽象,下面我們通過一個例子來描述該模式。

 例子

  我們舉一個吃火鍋的例子,根據裝飾者模式的特點:

  首先我們要有個共同的抽象,這里我們通過接口來實現,這個接口我們稱之為鍋底。  

/*
 * 鍋底
 */
public interface Hotpot {
    /** 描述 */
    String getName();
    /** 價格 */    
    Double getPrice();

}

  第二步,我們設計具體的鍋底類,我們分為醬香鍋、香辣鍋和清湯鍋,這是底鍋,每筆單都必須有且只有一個。

public class JamHotpot implements Hotpot{
    @Override
    public String getName() {
        return "醬香鍋";
    }

    @Override
    public Double getPrice() {
        return 4.0;
    }
}

public class SpicyHotpot implements Hotpot{
    @Override
    public String getName() {
        return "香辣鍋";
    }

    @Override
    public Double getPrice() {
        return 4.0;
    }
}

public class ClearSoupHotpot implements Hotpot{
    @Override
    public String getName() {
        return "清湯鍋";
    }

    @Override
    public Double getPrice() {
        return 3.0;
    }
}

  第三步,我們新增一個配菜接口,繼承共同的接口鍋底,這個接口用來作為所有配菜的父級,該接口可以拓展所以配菜的共有屬性

/*
 * 配菜
 */
public interface SideDish extends Hotpot {
    //可拓展配菜的公共屬性
}

  第四步,我們需要新增具體的配菜類,這里的配菜類我們注意到比鍋底類多了成員變量和構造方法,而且getName和getPrice方法多了加了傳入參數,這個就是為了動態的去附加功能,具體怎么實現參考最后一步。

/*
 * 牛肉
 */
public class Beef implements SideDish {

    private Hotpot hotpot;

    public Beef(Hotpot hotpot) {
        this.hotpot = hotpot;
    }

    @Override
    public String getName() {
        return hotpot.getName() + ",牛肉";
    }

    @Override
    public Double getPrice() {
        return hotpot.getPrice() + 38.0;
    }
}

/*
 * 生菜
 */
public class Lettuce implements SideDish {

    private Hotpot hotpot;

    public Lettuce(Hotpot hotpot) {
        this.hotpot = hotpot;
    }

    @Override
    public String getName() {
        return hotpot.getName() + ",生菜";
    }

    @Override
    public Double getPrice() {
        return hotpot.getPrice() + 8.0;
    }
}

  最后我們測試:

public class DecoratorTest {

    public static void main(String[] args) {
        System.out.println("=======醬香鍋底加牛肉");
        Hotpot hotpot = new JamHotpot();
        hotpot = new Beef(hotpot);
        hotpot = new Lettuce(hotpot);
        System.out.println("===火鍋的價格為:" + hotpot.getPrice() + "元");
        //如果我們需要更多的配菜參考上面的方式去添加更多的配菜  
    }
}

 總結

  如上面所描寫的那樣,我只需要前台傳遞給我們所點的鍋底和配菜,我們后台去動態的生成一個新的火鍋對象。這么設計的好處的拓展極其方便,就算這個火鍋店加了新的鍋底,或者是配菜,對我們之前的代碼是沒有任何影響的,這就是所謂的開閉原則(對拓展開放,對修改關閉),后面我們會講到設計模式相應的原則。除了上面的好處之外,裝飾者模式也有他本身不能忽視的問題,那就是每次生成一筆訂單都會生成很多小對象,如果該筆單對象很多的話,對我們的內存是個不小的考驗,而且過多的小類會讓我們的系統變得很復雜,讓人很難以理解。所以裝飾器模式有利有弊(更多的是利大於弊),我們可以好好思考裝飾者模式應用場景,然后進一步掌握這種設計思想。

 番外

  想了解裝飾者模式的更多詳細信息可以通過jdk源碼或者spring源碼去了解。jdk中IO操作就有通過裝飾者模式實現的,FilterInputStream和它的實現就是一個裝飾者模式,同樣的在spring源碼中,凡事以Decorator結尾的類都是實現的裝飾者模式,當然不是所有的裝飾器模式都是以Decorator結尾的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM