本文節(jié)選自《設(shè)計(jì)模式就該這樣學(xué)》

1 中介者模式的應(yīng)用場(chǎng)景

在現(xiàn)實(shí)生活中,中介者的存在是不可缺少的,如果沒(méi)有了中介者,我們就不能與遠(yuǎn)方的朋友進(jìn)行交流。各個(gè)同事對(duì)象將會(huì)相互進(jìn)行引用,如果每個(gè)對(duì)象都與多個(gè)對(duì)象進(jìn)行交互,則會(huì)形成如下圖所示的網(wǎng)狀結(jié)構(gòu)。

從上圖可以看到,每個(gè)對(duì)象之間都過(guò)度耦合,這樣既不利于信息的復(fù)用也不利于擴(kuò)展。如果引入中介者模式,則對(duì)象之間的關(guān)系將變成星形結(jié)構(gòu),如下圖所示。

從上圖可以看到,使用中介者模式后,任何一個(gè)類的變化,只會(huì)影響中介者和類本身,不像之前的設(shè)計(jì),任何一個(gè)類的變化都會(huì)引起其關(guān)聯(lián)的所有類的變化。這樣的設(shè)計(jì)大大減少了系統(tǒng)的耦合度。
其實(shí)日常生活中我們每天都在刷的朋友圈,就是一個(gè)中介者。還有我們所見(jiàn)的信息交易平臺(tái),也是中介者模式的體現(xiàn)。

中介者模式是用來(lái)降低多個(gè)對(duì)象和類之間的通信復(fù)雜性的。這種模式通過(guò)提供一個(gè)中介類,將系統(tǒng)各層次對(duì)象間的多對(duì)多關(guān)系變成一對(duì)多關(guān)系,中介者對(duì)象可以將復(fù)雜的網(wǎng)狀結(jié)構(gòu)變成以中介者為中心的星形結(jié)構(gòu),達(dá)到降低系統(tǒng)的復(fù)雜性、提高可擴(kuò)展性的作用。
若系統(tǒng)各層次對(duì)象之間存在大量的關(guān)聯(lián)關(guān)系,即層次對(duì)象呈復(fù)雜的網(wǎng)狀結(jié)構(gòu),如果直接讓它們緊耦合通信,會(huì)使系統(tǒng)結(jié)構(gòu)變得異常復(fù)雜,且當(dāng)其中某個(gè)層次對(duì)象發(fā)生改變時(shí),則與其緊耦合的相應(yīng)層次對(duì)象也需進(jìn)行修改,系統(tǒng)很難進(jìn)行維護(hù)。
簡(jiǎn)單地說(shuō),如果多個(gè)類相互耦合,形成了網(wǎng)狀結(jié)構(gòu),則考慮使用中介者模式進(jìn)行優(yōu)化??偨Y(jié)一下,中介者模式主要適用于以下應(yīng)用場(chǎng)景。

(1)系統(tǒng)中對(duì)象之間存在復(fù)雜的引用關(guān)系,產(chǎn)生的相互依賴關(guān)系結(jié)構(gòu)混亂且難以理解。

(2)交互的公共行為,如果需要改變行為,則可以增加新的中介者類。

2 中介者模式的UML類圖

中介者模式的UML類圖如下圖所示。

3 使用中介者模式設(shè)計(jì)群聊場(chǎng)景

假設(shè)我們要構(gòu)建一個(gè)聊天室系統(tǒng),用戶可以向聊天室發(fā)送消息,聊天室會(huì)向所有用戶顯示消息。實(shí)際上就是用戶發(fā)信息與聊天室顯示的通信過(guò)程,不過(guò)用戶無(wú)法直接將信息發(fā)給聊天室,而需要將信息先發(fā)到服務(wù)器上,然后服務(wù)器再將該消息發(fā)給聊天室進(jìn)行顯示,具體代碼如下。首先創(chuàng)建User類。

public class User {    private String name;    private ChatRoom chatRoom;    public User(String name, ChatRoom chatRoom) {        this.name = name;        this.chatRoom = chatRoom;    }    public void sendMessage(String msg) {        this.chatRoom.showMsg(this, msg);    }    public String getName() {        return name;    }}

然后創(chuàng)建ChatRoom類。

public class ChatRoom {    public void showMsg(User user, String msg) {        System.out.println("[" + user.getName() + "] :" + msg);    }}

最后編寫客戶端測(cè)試代碼。

public static void main(String[] args) {        ChatRoom room = new ChatRoom();        User tom = new User("Tom",room);        User jerry = new User("Jerry",room);        tom.sendMessage("Hi! I am Tom.");        jerry.sendMessage("Hello! My name is Jerry.");}

運(yùn)行結(jié)果如下圖所示。

4 中介者模式在JDK源碼中的應(yīng)用

首先來(lái)看JDK中的Timer類。打開(kāi)Timer的結(jié)構(gòu),我們發(fā)現(xiàn)Timer類中有很多schedule()重載方法,如下圖所示。

任意點(diǎn)開(kāi)其中一個(gè)方法,我們發(fā)現(xiàn)所有方法最終都調(diào)用了私有的schedule()方法,源碼如下。

public class Timer {    ...        public void schedule(TimerTask task, long delay) {        if (delay < 0)            throw new IllegalArgumentException("Negative delay.");        sched(task, System.currentTimeMillis()+delay, 0);    }    ...    private void sched(TimerTask task, long time, long period) {        if (time < 0)            throw new IllegalArgumentException("Illegal execution time.");        if (Math.abs(period) > (Long.MAX_VALUE >> 1))            period >>= 1;        synchronized(queue) {            if (!thread.newTasksMayBeScheduled)                throw new IllegalStateException("Timer already cancelled.");            synchronized(task.lock) {                if (task.state != TimerTask.VIRGIN)                    throw new IllegalStateException(                        "Task already scheduled or cancelled");                task.nextExecutionTime = time;                task.period = period;                task.state = TimerTask.SCHEDULED;            }            queue.add(task);            if (queue.getMin() == task)                queue.notify();        }    }    ...}

而且,不管是什么樣的任務(wù)都被加入一個(gè)隊(duì)列中按順序執(zhí)行。我們把這個(gè)隊(duì)列中的所有對(duì)象都稱為“同事”。同事之間的通信都是通過(guò)Timer來(lái)協(xié)調(diào)完成的,Timer承擔(dān)了中介者的角色。

關(guān)注微信公眾號(hào)『 Tom彈架構(gòu) 』回復(fù)“設(shè)計(jì)模式”可獲取完整源碼。

【推薦】Tom彈架構(gòu):30個(gè)設(shè)計(jì)模式真實(shí)案例(附源碼),挑戰(zhàn)年薪60W不是夢(mèng)

本文為“Tom彈架構(gòu)”原創(chuàng),轉(zhuǎn)載請(qǐng)注明出處。技術(shù)在于分享,我分享我快樂(lè)!
如果本文對(duì)您有幫助,歡迎關(guān)注和點(diǎn)贊;如果您有任何建議也可留言評(píng)論或私信,您的支持是我堅(jiān)持創(chuàng)作的動(dòng)力。關(guān)注微信公眾號(hào)『 Tom彈架構(gòu) 』可獲取更多技術(shù)干貨!