中介者模式(Mediator)

本文參考自:《JAVA設(shè)計(jì)模式》之中介者模式(Mediator)

1. 作用

中介者模式也稱為調(diào)停者模式,調(diào)停者模式是對(duì)象的行為模式。調(diào)停者模式包裝了一系列對(duì)象相互作用的方式,使得這些對(duì)象不必相互明顯引用。從而使它們可以較松散地耦合。當(dāng)這些對(duì)象中的某些對(duì)象之間的相互作用發(fā)生改變時(shí),不會(huì)立即影響到其他的一些對(duì)象之間的相互作用。從而保證這些相互作用可以彼此獨(dú)立地變化。

2. 需要中介者模式的原因

如下圖所示,這個(gè)示意圖中有大量的對(duì)象,這些對(duì)象既會(huì)影響別的對(duì)象,又會(huì)被別的對(duì)象所影響,因此常常叫做同事(Colleague)對(duì)象。這些同事對(duì)象通過(guò)彼此的相互作用形成系統(tǒng)的行為。從圖中可以看出,幾乎每一個(gè)對(duì)象都需要與其他的對(duì)象發(fā)生相互作用,而這種相互作用表現(xiàn)為一個(gè)對(duì)象與另一個(gè)對(duì)象的直接耦合。這就是過(guò)度耦合的系統(tǒng)。


未引入中介者模式的系統(tǒng)

通過(guò)引入調(diào)停者對(duì)象(Mediator),可以將系統(tǒng)的網(wǎng)狀結(jié)構(gòu)變成以中介者為中心的星形結(jié)構(gòu),如下圖所示。在這個(gè)星形結(jié)構(gòu)中,同事對(duì)象不再通過(guò)直接的聯(lián)系與另一個(gè)對(duì)象發(fā)生相互作用;相反的,它通過(guò)調(diào)停者對(duì)象與另一個(gè)對(duì)象發(fā)生相互作用。調(diào)停者對(duì)象的存在保證了對(duì)象結(jié)構(gòu)上的穩(wěn)定,也就是說(shuō),系統(tǒng)的結(jié)構(gòu)不會(huì)因?yàn)樾聦?duì)象的引入造成大量的修改工作。


引入中介者模式的系統(tǒng)
3. 結(jié)構(gòu)
中介者模式結(jié)構(gòu)

中介者模式的四個(gè)角色

  • 抽象的中介者(Mediator)
    定義出同事對(duì)象到調(diào)停者對(duì)象的接口,其中主要方法是一個(gè)(或多個(gè))事件方法。
  • 具體的中介者(ConcreteMediator)
    實(shí)現(xiàn)了抽象調(diào)停者所聲明的事件方法。具體調(diào)停者知曉所有的具體同事類,并負(fù)責(zé)具體的協(xié)調(diào)各同事對(duì)象的交互關(guān)系。
  • 抽象的同事類(Colleague)
    定義出調(diào)停者到同事對(duì)象的接口。同事對(duì)象只知道調(diào)停者而不知道其余的同事對(duì)象。
  • 具體的同事類(ConcreteColleague)
    所有的具體同事類均從抽象同事類繼承而來(lái)。實(shí)現(xiàn)自己的業(yè)務(wù),在需要與其他同事通信的時(shí)候,就與持有的調(diào)停者通信,調(diào)停者會(huì)負(fù)責(zé)與其他的同事交互。
4. 實(shí)現(xiàn)

抽象的中介者

public interface Mediator {
    void change(Colleague c);
}

具體的中介者

public class ConcreteMediator implements Mediator{
    
    private ConcreteColleagueA colleagueA;
    private ConcreteColleagueB colleagueB;
    
    public void setColleagueA(ConcreteColleagueA colleagueA) {
        this.colleagueA = colleagueA;
    }
    
    public void setColleagueB(ConcreteColleagueB colleagueB) {
        this.colleagueB = colleagueB;
    }
    
    @Override
    public void change(Colleague c) {
        if(c instanceof ConcreteColleagueA) {
            System.out.println(((ConcreteColleagueA) c).getName());
        }else if(c instanceof ConcreteColleagueB) {
            System.out.println(((ConcreteColleagueB) c).getName());
        }
        
    }
    
}

抽象的同事類

public abstract class Colleague {
    
    private Mediator mediator;
    
    public Colleague(Mediator mediator) {
        this.mediator = mediator;
    }
    
    public Mediator getMediator() {
        return this.mediator;
    }
    
    public abstract void operate();
}

具體的同事類

public class ConcreteColleagueA extends Colleague{

    private String name;
    public ConcreteColleagueA(Mediator mediator) {
        super(mediator);
    }
    
    public String getName() {
        return this.name;
    }
    
    @Override
    public void operate() {
        this.name = "colleagueA";
        getMediator().change(this);
    }
}
public class ConcreteColleagueB extends Colleague{

    private String name;
    public ConcreteColleagueB(Mediator mediator) {
        super(mediator);
    }
    
    public String getName() {
        return this.name;
    }
    @Override
    public void operate() {
        this.name = "colleagueB";
        getMediator().change(this);
    }
}

客戶端調(diào)用

public class MediatorPatternMain {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ConcreteMediator mediator = new ConcreteMediator();
        ConcreteColleagueA colleagueA = new ConcreteColleagueA(mediator);
        ConcreteColleagueB colleagueB = new ConcreteColleagueB(mediator);
        
        mediator.setColleagueA(colleagueA);
        mediator.setColleagueB(colleagueB);
        
        colleagueA.operate();
        colleagueB.operate();
    }

}
5. 具體實(shí)例

在日常生活中,我們經(jīng)常使用電腦來(lái)看電影,把這個(gè)過(guò)程描述出來(lái),簡(jiǎn)化后假定會(huì)有如下的交互過(guò)程:

(1)首先是光驅(qū)要讀取光盤上的數(shù)據(jù),然后告訴主板,它的狀態(tài)改變了。

(2)主板去得到光驅(qū)的數(shù)據(jù),把這些數(shù)據(jù)交給CPU進(jìn)行分析處理。

(3)CPU處理完后,把數(shù)據(jù)分成了視頻數(shù)據(jù)和音頻數(shù)據(jù),通知主板,它處理完了。

(4)主板去得到CPU處理過(guò)后的數(shù)據(jù),分別把數(shù)據(jù)交給顯卡和聲卡,去顯示出視頻和發(fā)出聲音。

要使用調(diào)停者模式來(lái)實(shí)現(xiàn)示例,那就要區(qū)分出同事對(duì)象和調(diào)停者對(duì)象。很明顯,主板是調(diào)停者,而光驅(qū)、聲卡、CPU、顯卡等配件,都是作為同事對(duì)象。


框架圖

抽象的中介者

public interface Mediator {
    void change(Colleague colleague);
}

具體的中介者-主板類

public class MainBoard implements Mediator{
    private CDReader cdReader;
    private CPU cpu;
    private SoundPlayer soundPlayer;
    private VideoPlayer videoPlayer;
    
    public void setCDReader(CDReader cdReader) {
        this.cdReader = cdReader;
    }
    
    public void setCPU(CPU cpu) {
        this.cpu = cpu;
    }
    
    public void setSoundPlayer(SoundPlayer soundPlayer) {
        this.soundPlayer = soundPlayer;
    }
    
    public void setVideoPlayer(VideoPlayer videoPlayer) {
        this.videoPlayer = videoPlayer;
    }
    
    @Override
    public void change(Colleague colleague) {
        if(colleague instanceof CDReader) {
            String cdReaderData = ((CDReader)colleague).getData();
            operateCPU(cdReaderData);
        }else if(colleague instanceof CPU) {
            List<String> cpuDataList = ((CPU)colleague).getDataList();
            operateSoundPlayer(cpuDataList.get(0));
            operateVideoPlayer(cpuDataList.get(1));
        }
    }
    
    private void operateCPU(String data) {
        cpu.operate(data);
    }
    
    private void operateSoundPlayer(String data) {
        soundPlayer.playSound(data);
    }
    
    private void operateVideoPlayer(String data) {
        videoPlayer.playVideo(data);
    }
}

抽象的同事類

public class Colleague {
    private Mediator mediator;
    
    public Colleague(Mediator mediator) {
        this.mediator = mediator;
    }
    
    public Mediator getMediator() {
        return this.mediator;
    }
    
}

具體的同事類-光驅(qū)類

public class CDReader extends Colleague{

    private String data;
    public CDReader(Mediator mediator) {
        super(mediator);
    }
    
    public String getData() {
        return this.data;
    }
    
    public void read() {
        this.data = "sound,video";
        getMediator().change(this);
    }
}

具體的同事類-CPU類

public class CPU extends Colleague{

    private List<String> dataList;
    
    public CPU(Mediator mediator) {
        super(mediator);
        dataList = new ArrayList<>();
    }
    
    public List<String> getDataList(){
        return dataList;
    }
    public void operate(String data) {
        String[] liStrings = data.split(",");
        dataList.add(liStrings[0]);
        dataList.add(liStrings[1]);
        getMediator().change(this);
    }
}

具體的同事類-聲卡類

public class SoundPlayer extends Colleague{
    
    public SoundPlayer(Mediator mediator) {
        super(mediator);
    }
    
    public void playSound(String sound) {
        System.out.println(sound);
    }
}

具體的同事類-顯卡類

public class VideoPlayer extends Colleague{
    
    public VideoPlayer(Mediator mediator) {
        super(mediator);
    }
    
    public void playVideo(String video) {
        System.out.println(video);
    }
}

客戶端調(diào)用

public class MediatorPatternDemoMain {

    public static void main(String[] args) {
        MainBoard mainBoard = new MainBoard();
        
        CDReader cdReader = new CDReader(mainBoard);
        CPU cpu = new CPU(mainBoard);
        SoundPlayer soundPlayer = new SoundPlayer(mainBoard);
        VideoPlayer videoPlayer = new VideoPlayer(mainBoard);
        
        mainBoard.setCDReader(cdReader);
        mainBoard.setCPU(cpu);
        mainBoard.setSoundPlayer(soundPlayer);
        mainBoard.setVideoPlayer(videoPlayer);
        
        cdReader.read();
        
    }

}

6. 中介者模式的優(yōu)缺點(diǎn)

優(yōu)點(diǎn)

  • 松散耦合
    調(diào)停者模式通過(guò)把多個(gè)同事對(duì)象之間的交互封裝到調(diào)停者對(duì)象里面,從而使得同事對(duì)象之間松散耦合,基本上可以做到互補(bǔ)依賴。這樣一來(lái),同事對(duì)象就可以獨(dú)立地變化和復(fù)用,而不再像以前那樣“牽一處而動(dòng)全身”了。
  • 集中控制交互
    多個(gè)同事對(duì)象的交互,被封裝在調(diào)停者對(duì)象里面集中管理,使得這些交互行為發(fā)生變化的時(shí)候,只需要修改調(diào)停者對(duì)象就可以了,當(dāng)然如果是已經(jīng)做好的系統(tǒng),那么就擴(kuò)展調(diào)停者對(duì)象,而各個(gè)同事類不需要做修改。
  • 多對(duì)多變成一對(duì)多
    沒(méi)有使用調(diào)停者模式的時(shí)候,同事對(duì)象之間的關(guān)系通常是多對(duì)多的,引入調(diào)停者對(duì)象以后,調(diào)停者對(duì)象和同事對(duì)象的關(guān)系通常變成雙向的一對(duì)多,這會(huì)讓對(duì)象的關(guān)系更容易理解和實(shí)現(xiàn)。

缺點(diǎn)

調(diào)停者模式的一個(gè)潛在缺點(diǎn)是,過(guò)度集中化。如果同事對(duì)象的交互非常多,而且比較復(fù)雜,當(dāng)這些復(fù)雜性全部集中到調(diào)停者的時(shí)候,會(huì)導(dǎo)致調(diào)停者對(duì)象變得十分復(fù)雜,而且難于管理和維護(hù)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,491評(píng)論 3 416
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,263評(píng)論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,946評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,708評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,186評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,409評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,939評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,774評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,976評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,209評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,641評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,872評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,650評(píng)論 3 391
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,958評(píng)論 2 373