1. 程式人生 > >Java設計模式之從[遊戲中開啟寶箱]分析中介者(Mediator)模式

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的《設計模式》一書中提到了,通常對話方塊中的控制元件存在著依賴關係,如一個特定的文字框內容為空時,某個按鈕置灰;列表框的一列選擇的一個表目可能會改變一個文字框的內容……那麼,我們可以為這些相互依賴的控制元件建立一箇中介類,來使得它們之間的耦合關係變得鬆散。說白了,其實就是相互依賴的控制元件狀態改變時,向同一個物件傳送訊息,由這個物件來重新設定這些依賴控制元件的狀態,這也就是中介者模式的中心思想。