一、引子
中介在現實生活中並不陌生,滿大街的房屋中介、良莠不齊的出國中介……。它們的存在是因為它們能給我們的生活帶來一些便利:租房、買房用不著各個小區裡瞎轉;出國留學也不用不知所措。
中介者模式在程序設計中也起到了類似的作用。
二、定義與結構
GOF給中介者模式下的定義是:用一個中介對象來封裝一系列的對象交互。中介者使各對象不需要顯式地相互引用,從而使其耦合松散,而且可以獨立地改變它們之間的交互。簡單點來說,將原來兩個直接引用或者依賴的對象拆開,在中間加入一個“中介”對象,使得兩頭的對象分別和“中介”對象引用或者依賴。
當然並不是所有的對象都需要加入“中介”對象。如果對象之間的關系原本一目了然,中介對象的加入便是“畫蛇添足”。
來看下中介者模式的組成部分吧。
1) 抽象中介者(Mediator)角色:抽象中介者角色定義統一的接口用於各同事角色之間的通信。
2) 具體中介者(Concrete Mediator)角色:具體中介者角色通過協調各同事角色實現協作行為。為此它要知道並引用各個同事角色。
3) 同事(Colleague)角色:每一個同事角色都知道對應的具體中介者角色,而且與其他的同事角色通信的時候,一定要通過中介者角色協作。
來自《設計模式》一書的類圖:
由於中介者的行為與要使用的數據與具體業務緊密相關,抽象中介者角色提供一個能方便很多對象使用的接口是不太現實的。所以抽象中介者角色往往是不存在的,或者只是一個標示接口。如果有幸能夠提煉出真正帶有行為的抽象中介者角色,我想同事角色對具體中介者角色的選擇也是策略的一種應用。
“恰到好處,過猶不及”。適合自己系統的便是最好的。
三、進一步討論
是否還記得應用廣泛的MVC分為哪三層?模型層(Model)、表現層(View)還有控制層(Control\Mediator)。控制層便是位於表現層與模型層之間的中介者。籠統地說MVC也算是中介者模式在框架設計中的一個應用。
由於中介者模式在定義上比較松散,在結構上和觀察者模式、命令模式十分相像;而應用目的又與結構模式“門面模式”有些相似。
在結構上,中介者模式與觀察者模式、命令模式都添加了中間對象——只是中介者去掉了後兩者在行為上的方向。因此中介者的應用可以仿照後兩者的例子去寫。但是觀察者模式、命令模式中的觀察者、命令都是被客戶所知的,具體哪個觀察者、命令的應用都是由客戶來指定的;而大多中介者角色對於客戶程序卻是透明的。當然造成這種區別的原因是由於它們要達到的目的不同。
從目的上看,中介者模式與觀察者模式、命令模式便沒有了任何關系,倒是與前面講過的門面模式有些相似。
但是門面模式是介於客戶程序與子系統之間的,而中介者模式是介於子系統與子系統之間的。這也注定了它們有很大的區別:門面模式是將原有的復雜邏輯提取到一個統一的接口,簡化客戶對邏輯的使用。它是被客戶所感知的,而原有的復雜邏輯則被隱藏了起來。而中介者模式的加入並沒有改變客戶原有的使用習慣,它是隱藏在原有邏輯後面的,使得代碼邏輯更加清晰可用。
前面已經陸陸續續的將中介者模式的特點寫了出來。這裡再總結一下。使用中介者模式最大的好處就是將同事角色解耦。這帶來了一系列的系統結構改善:提高了原有系統的可讀性、簡化原有系統的通信協議——將原有的多對多變為一對多、提高了代碼的可復用性……
但是中介者角色集中了太多的責任,所有有關的同事對象都要由它來控制。這不由得讓我想起了簡單工廠模式,但是由於中介者模式的特殊性——與業務邏輯密切相關,不能采用類似工廠方法模式的解決方法。因此建議在使用中介者模式的時候注意控制中介者角色的大小。
討論了這麼多關於中介者模式的特點。可以總結出中介者模式的使用時機:一組對象以定義良好但是復雜的方式進行通信,產生了混亂的依賴關系,也導致對象難以復用。
四、總結
中介者模式很容易在系統中應用,也很容易在系統中誤用。當系統出現了“多對多”交互復雜的對象群,不要急於使用中介者模式,而要先反思你的系統在設計上是不是合理。