Java設計模式之再從[暗黑破壞神"裝備鑲嵌寶石系統"]分析裝飾(Decorator)模式

來源:互聯網
上載者:User

  在暗黑破壞神等RPG遊戲中,會遇到如下的一些情境:我有一把很普通的武器,我通過給它“注入魔法力量”、“鑲嵌寶石”,來使得它擁有一些攻擊特效:例如,一把普通長劍,鑲嵌紅寶石後,可以附帶火焰傷害,鑲嵌了一個藍寶石後,可以使得長劍攻擊帶有冰凍傷害。

  如何?上述的機制呢?首先我們想到的是繼承,因為,一個鑲嵌了紅寶石、藍寶石的長劍,一定是一個鑲嵌了寶石的長劍,並且一定一把長劍。如此下來,程式的結構會很複雜,而且你可能會想,要是鑲嵌的是別的寶石怎麼辦呢?如果出了寶石外,可以鑲嵌其他物品(如符文),那是不是應該把繼承的結構改變呢?可見,繼承並不是一個最優的方案。

  仔細分析一下這種情況,我們會發現,所謂“火焰傷害”、“冰凍傷害”,只是一些“攻擊特效”,說白了就是長劍的攻擊的裝飾。我們僅僅是為了能夠在長劍攻擊的時候,增加一些職責:觸發火焰傷害、觸發冰凍傷害。這個時候我們就可以用到裝飾(Decorator)模式——它的意圖是動態地給一個對象添加一些額外的職責。就增加新功能來說,它比繼承更為靈活。

  假設我想給我的長劍賦予眩暈、暴擊和中毒攻擊三種特效,那麼Java代碼可以這樣寫:

interface Weapon{    void printInfo();}class Sword implements Weapon {    public void printInfo(){         System.out.println ("一把長劍");    }}abstract class WeaponDecorator implements Weapon {    public Weapon weapon;    public WeaponDecorator(Weapon _weapon){        weapon = _weapon;    }    public void printInfo(){        weapon.printInfo();    }}class PoisonDecorator extends WeaponDecorator {    public PoisonDecorator(Weapon _weapon) {        super(_weapon);    }    public void printInfo() {        weapon.printInfo();        //以下是自己添加的方法(裝飾)        System.out.println("  有50%幾率造成敵人中毒");    }}class CriticalDecorator extends WeaponDecorator {    public CriticalDecorator(Weapon _weapon) {        super(_weapon);    }    public void printInfo() {        weapon.printInfo();        //以下是自己添加的方法(裝飾)        System.out.println("  有50%幾率造成致命一擊");    }}class DazzleDecorator extends WeaponDecorator {    public DazzleDecorator(Weapon _weapon) {        super(_weapon);    }    public void printInfo() {        weapon.printInfo();        //以下是自己添加的方法(裝飾)        System.out.println("  有50%幾率造成敵人眩暈");    }}class Decorator{    public static void main(String[] args) {        Weapon superWeapon = new DazzleDecorator(new CriticalDecorator(new PoisonDecorator(new Sword())));        superWeapon.printInfo();    }}

  武器都繼承於Weapon介面,此介面聲明了一個方法:printInfo(),將武器的資訊列印出來。我們的裝飾器類WeaponDecorator中,包含了一個原始的Weapon對象引用,接下來是重點:當調用裝飾器類的printInfo時,它會先調用Weapon對象的printInfo,然後再調用自己額外增加的一些代碼。當然,調用Weapon.printInfo的順序可先可後,但是一定會調用到。也就是說,裝飾器類的重點是其中包含一個原始對象,在調用某個方法時,裝飾器類不僅僅會調用原始對象的這個方法,你還可以自己給它增加一些方法。如本例中,調用裝飾器類的printInfo時,先調用了weapon.printInfo(),再調用了我們希望它增加的職責System.out.println,那麼代碼運行結果如下:

一把長劍
  有50%幾率造成敵人中毒
  有50%幾率造成致命一擊
  有50%幾率造成敵人眩暈

  裝飾模式比繼承模式更加靈活(可以靈活添加職責),然而,我們必須要為每一個被裝飾的方法建立一個類,如果需要裝飾的方法很多,那麼我們會需要建立數量巨大的裝飾器類,這個時候就要考慮是否要用裝飾模式了。在Java.IO,C#的IO(如OutputStream)中就用到了裝飾器這種模式。需要注意到是,裝飾器類必須要與被裝飾的類繼承於同一介面,這就如最開始所說的,不管長劍鑲嵌了什麼,它總是一把武器。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.