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來建立一個新的寶石。