Java設計模式之從[遊戲中開啟寶箱]分析中介者(Mediator)模式
假設我們正在設計一個遊戲房間,房間裡有兩個按鈕和一個寶箱,如果我們按下了按鈕1,則按鈕2和寶箱均不可使用;如果我們按下了按鈕2,則按鈕1和寶箱均不可使用;如果我們開啟寶箱,則按鈕1不可按下。
在上面的例子中,我們可以看到兩個按鈕和一個寶箱之間存在著依賴關係,它們之間的狀態是有關聯的。假設按鈕類叫做Button,寶箱類叫做Chest,我們需要避免Button、Chest之間相互連線,我們應當建立一箇中介者類,當Button、Chest的狀態發生改變時,應當告訴中介者,由中介者來決定如何改變這些Button和Chest的屬性。
一個典型的中介者模式如上圖所示。Mediator為中介者的抽象,Colleague為共同協作的物件,如Button、Chest。我們用中介物件來封裝一系列物件的互動,中介者使物件不需要顯式地相互引用,從而使其耦合鬆散,而且可以獨立地改變它們之間的互動。
文章開始的例子實現如下:
interface Director{ void switchTriggered(Switch sw); void createSwitches(); } class RoomDirector implements Director{ private Button button1; private Button button2; private Chest chest; public Button getButton1() { return button1; } public void setButton1(Button button1) { this.button1 = button1; } public Button getButton2() { return button2; } public void setButton2(Button button2) { this.button2 = button2; } public Chest getChest() { return chest; } public void setChest(Chest chest) { this.chest = chest; } public void switchTriggered(Switch sw){ if (sw == button1){ System.out.println("按鈕1被按下"); button2.setEnabled(false); chest.setEnabled(false); } else if (sw == button2){ System.out.println("按鈕2被按下"); button1.setEnabled(false); chest.setEnabled(false); } else if (sw == chest){ System.out.println("箱子被開啟"); button1.setEnabled(false); } } public void createSwitches(){ button1 = new Button(this); button2 = new Button(this); chest = new Chest(this); } } abstract class Switch { private boolean enabled = true; public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } public Switch(Director director) { this.director = director; } private Director director; void triggered(){ director.switchTriggered(this); } } class Chest extends Switch{ public Chest(Director director) { super(director); } private boolean opened; public boolean isOpened() { return opened; } public void open() { if (isEnabled()){ opened = true; triggered(); } else { System.out.println("箱子不可用!"); } } } class Button extends Switch{ public Button(Director director) { super(director); } private boolean push; public boolean isPush() { return push; } public void push() { if (isEnabled()){ this.push = true; triggered(); } else { System.out.println("按鈕不可用!"); } } } public class Mediator { public static void main(String[] args) { RoomDirector room = new RoomDirector(); room.createSwitches(); room.getChest().open(); room.getButton1().push(); room.getButton2().push(); } }
Director為一箇中介類的抽象,它衍生出了RoomDirector。RoomDirectory裡包含了共同協作的3個物件,分別是兩個Button和一個Chest,它們均繼承於共同協作的Switch類。當Button被按下、Chest被開啟的時候,都會呼叫基類的trigger方法,以通知RoomDirector——"你的某一個物件的狀態改變了",緊接著呼叫RoomDirector裡面的switchTriggered方法,來對這3個物件進行操作。在main方法中,我們先打開了箱子,然後按了一下button1,此時button1應該是失效的,再按了一下button2,button2是有效的,因此程式的結果為:
箱子被開啟
按鈕不可用!
按鈕2被按下
可見,我們所有物件之間的互動動作,都寫在了switchTriggered方法中。在RoomDirector這個中介類中,如果需要管理的物件越多,則它會變得越來越複雜。在GoF的《設計模式》一書中提到了,通常對話方塊中的控制元件存在著依賴關係,如一個特定的文字框內容為空時,某個按鈕置灰;列表框的一列選擇的一個表目可能會改變一個文字框的內容……那麼,我們可以為這些相互依賴的控制元件建立一箇中介類,來使得它們之間的耦合關係變得鬆散。說白了,其實就是相互依賴的控制元件狀態改變時,向同一個物件傳送訊息,由這個物件來重新設定這些依賴控制元件的狀態,這也就是中介者模式的中心思想。