本文節選自《設計模式就該這樣學》

1 中介者模式的應用場景

在現實生活中,中介者的存在是不可缺少的,如果沒有了中介者,我們就不能與遠方的朋友進行交流。各個同事對象將會相互進行引用,如果每個對象都與多個對象進行交互,則會形成如下圖所示的網狀結構。

從上圖可以看到,每個對象之間都過度耦合,這樣既不利于信息的復用也不利于擴展。如果引入中介者模式,則對象之間的關系將變成星形結構,如下圖所示。

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

中介者模式是用來降低多個對象和類之間的通信復雜性的。這種模式通過提供一個中介類,將系統各層次對象間的多對多關系變成一對多關系,中介者對象可以將復雜的網狀結構變成以中介者為中心的星形結構,達到降低系統的復雜性、提高可擴展性的作用。
若系統各層次對象之間存在大量的關聯關系,即層次對象呈復雜的網狀結構,如果直接讓它們緊耦合通信,會使系統結構變得異常復雜,且當其中某個層次對象發生改變時,則與其緊耦合的相應層次對象也需進行修改,系統很難進行維護。
簡單地說,如果多個類相互耦合,形成了網狀結構,則考慮使用中介者模式進行優化??偨Y一下,中介者模式主要適用于以下應用場景。

(1)系統中對象之間存在復雜的引用關系,產生的相互依賴關系結構混亂且難以理解。

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

2 中介者模式的UML類圖

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

3 使用中介者模式設計群聊場景

假設我們要構建一個聊天室系統,用戶可以向聊天室發送消息,聊天室會向所有用戶顯示消息。實際上就是用戶發信息與聊天室顯示的通信過程,不過用戶無法直接將信息發給聊天室,而需要將信息先發到服務器上,然后服務器再將該消息發給聊天室進行顯示,具體代碼如下。首先創建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;    }}

然后創建ChatRoom類。

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

最后編寫客戶端測試代碼。

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.");}

運行結果如下圖所示。

4 中介者模式在JDK源碼中的應用

首先來看JDK中的Timer類。打開Timer的結構,我們發現Timer類中有很多schedule()重載方法,如下圖所示。

任意點開其中一個方法,我們發現所有方法最終都調用了私有的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();        }    }    ...}

而且,不管是什么樣的任務都被加入一個隊列中按順序執行。我們把這個隊列中的所有對象都稱為“同事”。同事之間的通信都是通過Timer來協調完成的,Timer承擔了中介者的角色。

關注微信公眾號『 Tom彈架構 』回復“設計模式”可獲取完整源碼。

【推薦】Tom彈架構:30個設計模式真實案例(附源碼),挑戰年薪60W不是夢

本文為“Tom彈架構”原創,轉載請注明出處。技術在于分享,我分享我快樂!
如果本文對您有幫助,歡迎關注和點贊;如果您有任何建議也可留言評論或私信,您的支持是我堅持創作的動力。關注微信公眾號『 Tom彈架構 』可獲取更多技術干貨!