設計模式系列之「中介者模式」

小Y在文章開始之前先回顧一下歷史:三省六部制是西晉以后長期發(fā)展形成,至隋朝正式確立,唐朝進一步完善的一種政治制度,反映了中國古代君主專制中央集權制度的進一步完善。那么小Y今天的主題就來了—如何最大實現(xiàn)“一省六部”(尚書省、吏部、戶部、禮部、兵部、刑部、工部)的效能,Action。

一、前提

尚書省管屬下的六部之間相互協(xié)調(diào)工作,來張圖展示一下這錯綜復雜、愛恨情仇的關系。


為了文章的簡潔,小Y不得不裁減部門了,把“一省六部”直接縮減為“一省三部”。


三個部門相互依賴的同時它們也有著自己的職能,小Y就有失偏頗地概括了一下:

  • 戶部:管理錢財。
  • 兵部:掌管兵權。
  • 工部:掌管營造工程事項。

二、情景再現(xiàn)

1.天災造成百姓流離失所,餓殍滿地,這下戶部麻煩了,心想著責任不能我一個人擔啊,死都要拉個墊背的。

  • 對兵部說:饑民太多,恐防出現(xiàn)暴亂,需要軍隊鎮(zhèn)壓。

  • 對工部說:災害損毀房屋太多,需要你們來規(guī)劃重建。

2.不長眼睛的蠻夷族要攻打天朝,兵部這下就坐不住了,立馬找來工部和戶部。

  • 對工部說:蠻夷族的戰(zhàn)斗力太強悍了,需要通過一些防御工事抵御,這事就交給你們了。

  • 對戶部說:要想打勝仗,士兵首先要吃得飽穿得暖,吃穿的錢糧這個重任就非你們莫屬了。

3.皇帝老爺?shù)腻佣嗔?,行宮要大批大批的建,工部就抱怨了,為毛皇帝這毛快活就要累死我們,不行,有苦同吃,有難各自飛,這才是兄弟嘛。

  • 對兵部說:陛下要求大規(guī)模建行宮,為陛下服務的機會到了哈,調(diào)遣大批士兵給我當苦力吧。

  • 對戶部說:行官需要設計精美,需要花費的銀子不少,需要你們搜刮多點民脂民膏。

三、出謀劃策

  • 方案一:尚書省只掛個管理牌就可以,對下面六個部門的工作不干預,愛咋干咋干,關鍵時刻給我功勞就好。

  • 以尚書省為中心,底下六個部門在工作上不直接進行交流,統(tǒng)一經(jīng)過尚書
    ?。ㄖ薪檎吣J剑?/p>

四、來波廣告

1.中介模式的定義

用一個中介對象封裝一系列的對象交互,中介者使各對象不需要顯示地相互作用,從而使其耦合松散,而且可以獨立地改變它們之間的交互。

2.中介模式的角色介紹

  • Mediator 抽象中介者角色
    抽象中介者角色定義統(tǒng)一的接口,用于各同事角色之間的通信。

  • Concrete Mediator 具體中介者角色
    具體中介者角色通過協(xié)調(diào)各同事角色實現(xiàn)協(xié)作行為,因此它必須依賴于各個同事角色。

  • Colleague 同事角色
    每一個同事角色都知道中介者角色,而且與其他的同事角色通信的時候,一定要通過中介者角色協(xié)作。每個同事類的行為分為兩種:一種是同事本身的行為,比如改變對象本身的狀態(tài),處理自己的行為等,這種行為叫做自發(fā)行為,與其他的同事類或中介者沒有任何的依賴;第二種是必須依賴中介者才能完成的行為,叫做依賴方法。

3.中介模式的使用場景

  • 在面向?qū)ο蟮木幊讨?,對象和對象之間必然會有依賴關系。

  • 中介者模式適用于多個對象之間緊密耦合的情況,緊密耦合的標準是:在類圖中出現(xiàn)了蜘蛛網(wǎng)狀結構。

五、方案的實施

1.方案一

發(fā)生事情各個部門自行商量解決。

①戶部

public class Department {

    public void dealDisaster(){
        System.out.println("戶部:專挑輕活,其他的找別人干去。");
        //需要工部規(guī)劃重建
        Ministry ministry=new Ministry();
        ministry.selfFunction();
        //需要兵部調(diào)兵遣將鎮(zhèn)壓災民
        Defense defense=new Defense();
        defense.selfFunction();

    }

    public void selfFunction(){
        System.out.println("戶部:要錢沒問題,我盡量搜刮點民脂民膏。");
    }
}

②兵部

public class Defense {

    public void fight(){
        System.out.println("我只出人,剩下的找別人干去。");
        //需要戶部搜刮民脂民膏
        Department department=new Department();
        department.selfFunction();
        //需要工部給圖紙建造防御工事
        Ministry ministry=new Ministry();
        ministry.selfFunction();
    }

    public void selfFunction(){
        System.out.println("兵部:要人沒問題,我盡量抓多幾個壯丁");
    }
}

③工部

public class Ministry {

    public void buildPalace(){
        System.out.println("工部:我只畫圖紙,其他的找別人干去。");
        //需要戶部出錢
        Department department=new Department();
        department.selfFunction();
        //需要兵部調(diào)兵遣將加入建造
        Defense defense=new Defense();
        defense.selfFunction();
    }

    public void selfFunction(){
        System.out.println("工部:要建筑圖紙沒問題,我盡量復制多幾份");
    }
}

④Client

public class Client {
    public static void main(String[] args) {
        //發(fā)生天災了,戶部麻煩了,需要解決問題
        Department department=new Department();
        department.dealDisaster();
        //要打仗了,兵部的活來了
        Defense defense=new Defense();
        defense.fight();
        //皇帝發(fā)話了,工部趕緊建行宮
        Ministry ministry=new Ministry();
        ministry.buildPalace();
    }
}

輸出的結果為:

//發(fā)生天災了,戶部麻煩了,需要解決問題
戶部:專挑輕活,其他的找別人干去。
工部:要建筑圖紙沒問題,我盡量復制多幾份。
兵部:要人沒問題,我盡量抓多幾個壯丁。

//要打仗了,兵部的活來了
兵部:我只出人,剩下的找別人干去。
戶部:要錢沒問題,我盡量搜刮點民脂民膏。
工部:要建筑圖紙沒問題,我盡量復制多幾份。

//皇帝發(fā)話了,工部趕緊建行宮
工部:我只畫圖紙,其他的找別人干去。
戶部:要錢沒問題,我盡量搜刮點民脂民膏。
兵部:要人沒問題,我盡量抓多幾個壯丁。

三個部門遇到問題都相互協(xié)調(diào)解決了,沒出什么幺蛾子,尚書省也照樣得到功勞獎勵。從上面的例子發(fā)現(xiàn)這三個類是彼此關聯(lián)的,每個類都與其他兩個類產(chǎn)生了關聯(lián)關系。這樣子缺點就暴露出來了,它們彼此關聯(lián)越多,耦合性越大,要想修改一個就得修改一片,這不是面向?qū)ο笤O計所期望的,上面的例子還是僅三個部門的情況,如果實現(xiàn)上圖的六部之間的協(xié)調(diào)關系,維護起來都要吐血而亡,果斷拋棄。

2.方案二(中介者模式)

UML實現(xiàn)
①抽象中介者(尚書?。?/h5>
public abstract class AbstractMediator {

    protected Department department;
    protected Defense defense;
    protected Ministry ministry;

    public AbstractMediator() {
        department = new Department(this);
        defense=new Defense(this);
        ministry=new Ministry(this);
    }
    
    //中介者最重要的方法叫做事件方法,處理多個對象之間的關系
    public abstract void dealThing(int code);
}
②具體中介者
public class Mediator extends AbstractMediator{

    public static final int DEPARTMENT_CODE=1;
    public static final int DEFENSE_CODE=2;
    public static final int MINISTRY_CODE=3;

    @Override
    public void dealThing(int code) {
        switch (code){
            case DEPARTMENT_CODE:
                this.dealDisaster();
                break;
            case DEFENSE_CODE:
                this.fight();
                break;
            case MINISTRY_CODE:
                this.buildPalace();
                break;
        }
    }
    //戶部處理天災
    private void dealDisaster(){
        System.out.println("戶部:專挑輕活,其他的找別人干去。");
        super.ministry.selfFunction();
        super.defense.selfFunction();
    }
    //兵部打仗
    private void fight(){
        System.out.println("兵部:我只出人,剩下的找別人干去。");
        super.department.selfFunction();
        super.ministry.selfFunction();
    }
    //工部建行宮
    private void buildPalace(){
        System.out.println("工部:我只畫圖紙,其他的找別人干去。");
        super.department.selfFunction();
        super.defense.selfFunction();
    }
}
③抽象部門類
public abstract class AbstractColleague {
    protected AbstractMediator abstractMediator;

    public AbstractColleague(AbstractMediator abstractMediator) {
        this.abstractMediator = abstractMediator;
    }
}
④戶部
public class Department extends AbstractColleague{

    public Department(AbstractMediator  abstractMediator) {
    super(abstractMediator);
    }

    public void dealDisaster(){
        super.abstractMediator.dealThing(Mediator.DEPARTMENT_CODE);
    }

    public void selfFunction(){
        System.out.println("要錢沒問題,我盡量搜刮點民脂民膏。");
    }
}
⑤兵部
public class Defense extends AbstractColleague{

    public Defense(AbstractMediator abstractMediator) {
        super(abstractMediator);
    }

    public void fight(){
        super.abstractMediator.dealThing(Mediator.MINISTRY_CODE);
    }

    public void selfFunction(){
        System.out.println("兵部:要人沒問題,我盡量抓多幾個壯丁");
    }
}
⑥工部
public class Ministry extends AbstractColleague{

    public Ministry(AbstractMediator abstractMediator) {
        super(abstractMediator);
    }

    public void buildPalace(){
        super.abstractMediator.dealThing(Mediator.MINISTRY_CODE);
    }

    public void selfFunction(){
        System.out.println("要建筑圖紙沒問題,我盡量復制多幾份");
    }
}
⑦Client
public class Client {
    public static void main(String[] args) {
        AbstractMediator abstractMediator=new Mediator();
        //發(fā)生天災了,戶部麻煩了,需要解決問題
        Department department=new Department(abstractMediator);
        department.dealDisaster();
        //要打仗了,兵部的活來了
        Defense defense=new Defense(abstractMediator);
        defense.fight();
        //皇帝發(fā)話了,工部趕緊建行宮
        Ministry ministry=new Ministry(abstractMediator);
        ministry.buildPalace();
    }
}

輸出的結果為:

//發(fā)生天災了,戶部麻煩了,需要解決問題
戶部:專挑輕活,其他的找別人干去。
工部:要建筑圖紙沒問題,我盡量復制多幾份。
兵部:要人沒問題,我盡量抓多幾個壯丁。

//要打仗了,兵部的活來了
兵部:我只出人,剩下的找別人干去。
戶部:要錢沒問題,我盡量搜刮點民脂民膏。
工部:要建筑圖紙沒問題,我盡量復制多幾份。

//皇帝發(fā)話了,工部趕緊建行宮
工部:我只畫圖紙,其他的找別人干去。
戶部:要錢沒問題,我盡量搜刮點民脂民膏。
兵部:要人沒問題,我盡量抓多幾個壯丁。
(1)建立了兩個抽象類AbstractMediator和AbstractColeague,每個對象只是與中介者Mediator之間產(chǎn)生依賴,與其他對象之間沒有直接關系。
(2)中介者Mediator定義了多個private方法,其目的是處理各個對象之間的依賴關系,就是說把原有一個對象要依賴多個對象的情況移到中介者的private方法中實現(xiàn)。
(3)在場景類中增加了一個中介者,然后分別傳遞到三個同事類中,三個類都具有相同的特性:只負責處理自己的活動(行為),與自己無關的活動就丟給中介者處理。
(4)在多個對象依賴的情況下,通過加入中介者角色,取消了多個對象的關聯(lián)或依賴關系,減少了對象的耦合性。

六、中介者模式優(yōu)缺點

1.優(yōu)點

中介者模式的優(yōu)點就是減少類間的依賴,把原有的一對多的依賴變成了一對一的依賴,同事類只依賴中介者,減少了依賴,當然同時也降低了類間的耦合。

2.缺點

中介者模式的缺點就是中介者會膨脹得很大,而且邏輯復雜,原本N個對象直接的相互依賴關系轉(zhuǎn)換為中介者和同事類的依賴關系,同事類越多,中介者的邏輯就越復雜。

七、簡單對比觀察者模式和中介者模式的區(qū)別

1.多個對象之間需要交互,那么這些對象間的交互就會形成網(wǎng)狀結構。引入中介者,各對象根本不知道其它對象的存在,他們只需要把信息發(fā)送給中介者,由中介者來控制把信息傳遞給哪些對象。
2.觀察者依賴于被觀察者的狀態(tài)改變,兩者之間是需要交互的。

八、總結

中介者模式是一個非常好的封裝模式,也是一個很容易被濫用的模式,要根據(jù)實際情況考慮是否選用中介模式,使用中介模式就必然會帶來中介者的膨脹問題,這一點一定要清楚。
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

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

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