1. 程式人生 > >Java設計模式之從[暗黑破壞神"裝備鑲嵌寶石系統"]分析橋接(Bridge)模式

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

  暴雪公司著名的遊戲暗黑破壞神中,有一個經典的"鑲嵌系統",例如,可以為武器鑲嵌紅寶石、藍寶石來得到攻擊特效或攻擊力加成,為防具鑲嵌紅寶石、藍寶石來得到攻擊特效或者防禦力的加成。不同的寶石加在不同的裝備上會有不同效果,如寶石加在武器上則提升武器攻擊力,加在防具上則提升防禦力。

  假設我們建立了一個劍類(Sword)和一個盾類(Shield),建立了一個紅寶石類(Ruby)和一個藍寶石類(Sapphire)。由於裝備可以鑲嵌寶石,那麼這兩個部分是可以兩兩組合的,為此,我們必須要寫出4個類來表示它們的全部組合: SwordWithRuby, SwordWithSapphire, ShieldWithRuby, ShieldWithSapphire,程式碼編寫十分繁瑣。產生這種情況的原因是,“裝備鑲嵌寶石”存在這兩個維度的變化(武器種類,寶石種類),假設有n種武器,m種寶石,為了實現這個機制,我們不得不構造m * n個類。

  這個時候,我們可以用橋接模式來進行設計。

  橋接模式的意圖是將抽象部分與它的實現部分分離,使它們可以獨立變化。在鑲嵌系統中,抽象部分是什麼?抽象部分就是武器鑲嵌寶石的一個抽象類(EquipmentRubyBridge);實現部分是什麼?實現部分是每種寶石的效果(Jewel)。程式碼如下:

interface Jewel {
    String name() ;
}

class Ruby implements Jewel {
    public String name (){
        return "紅寶石";
    }
}

class Sapphire implements Jewel {
    public String name (){
        return "藍寶石";
    }
}

class Sword extends EquipmentRubyBridge{
    public Sword(Jewel j) {
        super(j);
    }
    public void print(){
        System.out.println("為劍嵌入了一顆" + getJewel().name() );
    }
}

class Shield extends EquipmentRubyBridge{
    public Shield(Jewel j) {
        super(j);
    }
    public void print(){
        System.out.println("為盾嵌入了一顆" + getJewel().name() );
    }
}

abstract class EquipmentRubyBridge{
    private Jewel jewel;
    protected Jewel getJewel () { return jewel;}
    public EquipmentRubyBridge(Jewel j){
        jewel = j;
    }
    public abstract void print();
}


class Bridge {
    public static void main(String[] args) {
        Jewel sapphire = new Sapphire();
        Jewel ruby = new Ruby();
        EquipmentRubyBridge sword = new Sword(ruby);
        EquipmentRubyBridge shield = new Shield(sapphire);
        sword.print();
        shield.print();
    }
}
執行結果:

為劍嵌入了一顆紅寶石
為盾嵌入了一顆藍寶石

  簡要分析一下上面的程式碼。EquipmentRubyBridge是鑲嵌機制的抽象,它規定了它的子類中包含了Jewel介面,Jewel介面為寶石的實現介面。對於EquipmentRubyBridge的子類,它必然組合了一個Jewel物件,也就是說,EquipmentRubyBridge如同一個橋樑,將它的子類和實現部分(Jewel)組合在了一起。如Shield類,繼承於EquipmentRubyBridge,在print方法中,呼叫了Jewel的getJewel().name()方法 —— EquipmentRubyBridge子類可以自己擴充print方法,也可以傳入各種Jewel類,這樣就實現了抽象部分和實現部分的獨立。

  在《設計模式》中說,當不希望在抽象和它的實現之間有一個固定的繫結模式時(本例中,武器並沒有和特定寶石做繫結)時可以用橋接。類的抽象以及它的實現都應該可以通過生成子類的方法進行擴充。如我們可以繼承EquipmentRubyBridge建立一個新的武器,或者繼承Jewel來建立一個新的寶石。