日常生活中每天在刷的朋友圈,沒有中間商賺差價的中介者模式剖析

中介者模式(Mediator Pattern)又稱為調解者模式或者調停者模式。用一箇中介物件封裝一系列的物件互動,中介者使各物件不需要顯示地互相作用,從而使其鬆散耦合,而且可以獨立的改變他們之間的互動。

中介者模式包裝了一系列物件相互作用的方式,使得這些物件不必相互明顯作用。當某些物件之間的作用發生改變時,不會立即影響其它的一些物件之間的作用。保證這些作用可以彼此獨立的變化。其核心思想是,透過中介者解耦系統各層次物件的直接耦合,層次物件的對外依賴通訊統統交由中介者轉發。

一、中介者模式的應用場景

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

日常生活中每天在刷的朋友圈,沒有中間商賺差價的中介者模式剖析

從上面的圖可以發現,每個物件之間過度耦合,這樣既不利於資訊的複用也不利於擴充套件。如果引入了中介者模式,那麼物件之間的關係將變為星狀結構,採用中介者模式後如下圖所示:

日常生活中每天在刷的朋友圈,沒有中間商賺差價的中介者模式剖析

引入中介者模式後,任何一個類的變化,只會影響中介者合類本身,之前的設計是任何一個類的變化都會引起其關聯所有類的變化。這樣的設計減少了系統的耦合度。

其實在我們日常生活中每天在刷的微信朋友圈,就是一箇中介者。還有資訊交易平臺,也是中介者模式的體現。

日常生活中每天在刷的朋友圈,沒有中間商賺差價的中介者模式剖析

日常生活中每天在刷的朋友圈,沒有中間商賺差價的中介者模式剖析

中介者模式是用來降低多個物件和類之間的通訊複雜性。這種模式透過提供一箇中介類,將系統各層次物件間的多對多關係變成一對多關係,中介者物件可以將複雜的網狀結構變成以調停者為中心的星形結構,達到降低系統的複雜性,提高可擴充套件性的作用。

若系統各層次物件之間存在大量的關聯關係,即層次物件呈複雜的網狀結構,如果直接讓它們緊耦合通訊,會造成系統結構變得異常複雜,且其中某個層次物件發生改變,則與其緊耦合的相應層次物件也需進行修改,系統很難進行維護。而透過為該系統增加一箇中介者層次物件讓其他各層次需對外通訊的行為統統交由中介者進行轉發,系統呈現以中介者為中心進行通訊的星形結構,系統的複雜性大大降低。

簡單的說如果多個類相互耦合,形成了網狀結構,則需要考慮使用中介者模式進行最佳化處理。中介者模式適用以下幾個場景:

系統中物件之間存在複雜的引用關係,產生的相互依賴關係結構混亂且難以理解;

互動的公共行為,如果需要改變行為則可以新增新的中介者類。

中介者模式主要包含4個角色:

抽象中介者(Mediator):定義統一的介面,使用者各個同事角色間的通訊;

具體中介者(ConcreateMediator):從具體的同事物件接收訊息,協調各同事物件間的協作;

抽象同事類(Colleague):每一個同事物件均需要依賴中介者角色,與其他同事通訊時,交由中介者進行轉發;

具體同事類(ConcreteColleague):負責實現自發行為(Self-Method),轉發依賴方法(Dep-Method)交由中介者進行協調。

1。1 簡易聊天室系統使用中介者模式

假設我們要構建一個聊天室系統,使用者可以向聊天室傳送訊息,聊天室會向所有的使用者顯示訊息。實際上就是使用者發信息與聊天室顯示的通訊過程,不過使用者無法直接將資訊發給聊天室,而是需要將資訊先發到伺服器上,然後伺服器再將該訊息發給聊天室進行顯示。具體程式碼如下。

建立User類:

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

建立聊天室ChatRoom類:

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

測試main方法:

public static void main(String[] args) { ChatRoom chatRoom = new ChatRoom(); User kevin = new User(“Kevin”, chatRoom); User jhon = new User(“Jhon”, chatRoom); kevin。sendMsg(“Hello, Jhon!”); jhon。sendMsg(“Hi, Kevin!”);}

執行結果:

日常生活中每天在刷的朋友圈,沒有中間商賺差價的中介者模式剖析

二、中介者模式在原始碼中的體現

JDK中的Timer類

開啟Timer類的結構圖我們發現Timer類中有很多schedule()方法過載,如下圖:

日常生活中每天在刷的朋友圈,沒有中間商賺差價的中介者模式剖析

任意點開其中的一個方法,發現所有的方法最終都是呼叫了私有的sched()方法,看下它們的原始碼:

private void sched(TimerTask task, long time, long period) { if (time < 0) throw new IllegalArgumentException(“Illegal execution time。”); // Constrain value of period sufficiently to prevent numeric // overflow while still being effectively infinitely large。 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承擔了中介者的角色。

三、中介者模式的優缺點

優點

減少類間依賴,將多對多依賴轉化成了一對多,降低了類間耦合;

類間各司其職,符合迪米特法則。

缺點

中介者模式中將原本多個物件直接的相互依賴變成了中介者和多個同事類的依賴關係。當同事類越多時,中介者就會越臃腫,變得複雜且難以維護。