學(xué)好設(shè)計模式防被祭天:中介者模式

中介者模式

為了防止被“殺”了祭天,學(xué)點設(shè)計模式,并總結(jié)下還是有必要的。

一:理解

  1. 對象之間相互依賴調(diào)用會導(dǎo)致結(jié)構(gòu)混亂。在中介者模式中,對象發(fā)起調(diào)用后,首先會經(jīng)過中介者對象的路由,然后才將消息發(fā)送給被調(diào)用者。
  2. 中介者模式實現(xiàn)了調(diào)用者和被調(diào)用者的解耦,特別是在調(diào)用關(guān)系復(fù)雜的情況下,中介者的效果更為明顯。
  3. 中介者模式可以將對象間復(fù)雜的網(wǎng)狀調(diào)用關(guān)系重構(gòu)成清晰的星型關(guān)系。
  4. 就像租房子的時候,房客可以直接找到中介,中介幫房客去和房東交流。房客可以通過中介和多個房東取得聯(lián)系,同樣的,房東可以通過中介和多個房客取得聯(lián)系。


二:例子

你是個富二代。

你家有很多仆人,為了方便,只例舉司機(jī)和廚師。

你家特別大,你和仆人們之間的交流基本靠高科技通信。

當(dāng)你發(fā)消息時,仆人們都應(yīng)該收到。

當(dāng)司機(jī)發(fā)消息時,只有你會收到,因為其他仆人沒有這個權(quán)利。

當(dāng)廚師發(fā)消息時,你和其他仆人都會收到,畢竟各位吃貨都不想錯過用餐時間。

由于仆人實在太多,你叫來了程序員小菜幫忙抽象一下。

小菜考慮到:

  1. 可以使用觀察者模式,當(dāng)你發(fā)消息的時候,仆人們都會收到。但這樣你需要持有所有仆人的對象,而且在這個需求中,仆人們也能發(fā)送消息,所以你們之間必然會有相互引用。
  2. 可以使用中介者模式,所有人都把消息發(fā)送給中介者,然后再由中介者進(jìn)行消息轉(zhuǎn)發(fā)。

小菜上來就是一頓敲。

他首先抽象出一個中介者接口,含有一個接受消息方法acceptMessageFromRole,其中參數(shù)msg表示消息內(nèi)容,role表示發(fā)送的角色,如你,司機(jī)等。

public interface MediatorI {
    void acceptMessageFromRole(String msg, Role role);
}

接著,他寫了一個角色抽象類。

@Data
public abstract class Role {
    protected MediatorI mediator;

    public abstract void sendMessageToMediator(String msg);

    public abstract void acceptMessageFromMediator(String msg);
}

在該類中,包含一個中介者mediator屬性,因為角色需要將消息發(fā)送到中介者。

還包含發(fā)送消息給中介者方法sendMessageToMediator和從中介者接受消息方法acceptMessageFromMediator。

接著,小菜分別抽象了富二代類,司機(jī)類和廚師類。

// 富二代類
public class FuErDai extends Role {
    @Override
    public void sendMessageToMediator(String msg) {
        System.out.println("富二代發(fā)送消息了,內(nèi)容是: " + msg);
        mediator.acceptMessageFromRole(msg, this);
    }

    @Override
    public void acceptMessageFromMediator(String msg) {
        System.out.println("富二代接到消息了,內(nèi)容是: " + msg);
    }
}

// 司機(jī)類
public class Driver extends Role {
    @Override
    public void sendMessageToMediator(String msg) {
        System.out.println("司機(jī)發(fā)送消息了,內(nèi)容是: "+msg);
        mediator.acceptMessageFromRole(msg, this);
    }

    @Override
    public void acceptMessageFromMediator(String msg) {
        System.out.println("司機(jī)接到消息了,內(nèi)容是: "+msg);
    }
}

// 廚師類
public class Cook extends Role {
    @Override
    public void sendMessageToMediator(String msg) {
        System.out.println("廚師發(fā)送消息了,內(nèi)容是: " + msg);
        mediator.acceptMessageFromRole(msg, this);
    }

    @Override
    public void acceptMessageFromMediator(String msg) {
        System.out.println("廚師接到消息了,內(nèi)容是: " + msg);
    }
}

三個角色都繼承自角色抽象類Role,又各自實現(xiàn)了抽象方法。

其中發(fā)消息方法sendMessageToMediator調(diào)用了中介者的接受消息方法,而收消息方法acceptMessageFromMediator只是簡單地打印消息。

在中介者模式中,需要有一個類來扮演中介者的角色,如同路由器在網(wǎng)絡(luò)傳輸中的角色。

在你家,你希望這個角色由管家來擔(dān)任。

于是小菜寫了管家類Housekeeper。

public class Housekeeper implements MediatorI {
    private FuErDai fuErDai;
    private Driver driver;
    private Cook cook;

    public Housekeeper(FuErDai fuErDai, Driver driver, Cook cook) {
        this.fuErDai = fuErDai;
        this.driver = driver;
        this.cook = cook;
    }

    @Override
    public void acceptMessageFromRole(String msg, Role role) {
        if (role instanceof FuErDai) {
            driver.acceptMessageFromMediator(msg);
            cook.acceptMessageFromMediator(msg);
        } else if (role instanceof Driver) {
            fuErDai.acceptMessageFromMediator(msg);
        } else if (role instanceof Cook) {
            fuErDai.acceptMessageFromMediator(msg);
            driver.acceptMessageFromMediator(msg);
        }
    }
}

管家類繼承自MediatorI接口,持有富二代,司機(jī),廚師對象屬性。

在acceptMessageFromRole方法中,管家會判斷消息的來源,如果是來自富二代,就需要轉(zhuǎn)發(fā)給司機(jī)和廚師,即分別調(diào)用司機(jī)和廚師的acceptMessageFromMediator方法。

測試代碼:

public class Client {
    public static void main(String[] args) {
        FuErDai fuErDai = new FuErDai();
        Driver driver = new Driver();
        Cook cook = new Cook();
        Housekeeper housekeeper = new Housekeeper(fuErDai, driver, cook);
        fuErDai.setMediator(housekeeper);
        driver.setMediator(housekeeper);
        cook.setMediator(housekeeper);
        //
        fuErDai.sendMessageToMediator("寶寶不開心了!");
        System.out.println();
        driver.sendMessageToMediator("寶寶要開車了!");
        System.out.println();
        cook.sendMessageToMediator("吃飯了!");
    }
}

可以看到,角色之間不用再相互引用,只需要持有相同的中介者對象即可,對象之間的調(diào)用變得非常清晰。

輸入/輸出:

富二代發(fā)送消息了,內(nèi)容是: 寶寶不開心了!
司機(jī)接到消息了,內(nèi)容是: 寶寶不開心了!
廚師接到消息了,內(nèi)容是: 寶寶不開心了!

司機(jī)發(fā)送消息了,內(nèi)容是: 寶寶要開車了!
富二代接到消息了,內(nèi)容是: 寶寶要開車了!

廚師發(fā)送消息了,內(nèi)容是: 吃飯了!
富二代接到消息了,內(nèi)容是: 吃飯了!
司機(jī)接到消息了,內(nèi)容是: 吃飯了!


三:再理解

  1. 在例子中,角色在接受消息之后只是簡單的打印消息。如果需要返回值,則被調(diào)用者需要給調(diào)用者發(fā)送一個消息,并且需要記錄發(fā)送者的信息。
  2. 雖然調(diào)用者和被調(diào)用者之間的關(guān)系變得清晰,但中介者的邏輯并不清晰。中介者需要判斷消息發(fā)送者并做出不同的響應(yīng),并且持有所有調(diào)用者對象。
  3. 當(dāng)需要加入新的角色時,需要對中介者代碼進(jìn)行修改。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容