中介者模式又稱調停者模式,屬于行為型模式;中介者模式包裝了一系列物件相互作用的方式,使得這些物件不必互相明顯參考,從而使它們可以較松散地耦合,當這些物件中的某些物件之間的相互作用發生改變時,不會立即影響到其他的一些物件之間的相互作用,從而保證這些相互作用可以彼此獨立地變化,
在中介者模式中,所有的成員物件都與一個處于中心地位的中介者物件發生緊密的聯系,由這個中介者物件進行協調作業,所有被協調的物件稱為同事物件,在所有同事物件內部發生的事件會影響到其他的同事物件,但是這種影響不是以直接管理的方式直接傳到其他的物件上的,僅僅直接影響到中介者物件,而由中介者物件反過來協調其他的同事,形成整個系統的行為,
為什么需要中介者模式
在實際開發中,一個系統可能會呼叫周邊的很多系統,那么在這個系統有大量的其他系統的實體物件,這些物件既會影響別的物件,又會被別的物件所影響,因此常常叫做同事(Colleague)物件,這些同事物件通過彼此的相互作用形成系統的行為,如下圖所示,幾乎每一個物件都需要與其他的物件發生相互作用,而這種相互作用表現為一個物件與另一個物件的直接耦合,這是一個過度耦合的系統,

通過引入中介者物件(Mediator),可以將系統的網狀結構變成以中介者為中心的星形結構,如下圖所示,在這個星形結構中,同事物件不再通過直接的聯系與另一個物件發生相互作用;相反地,它通過調停者物件與另一個物件發生相互作用,調停者物件的存在保證了物件結構上的穩定,也就是說,系統的結構不會因為新物件的引入造成大量的修改作業,

比起傳統的設計方法,面向物件的技術可以更好地協助開發者管理更為復雜的系統,一個好的面向物件的設計可以使物件之間增加協作性(Collaboration),減少耦合度(Coupling),一個深思熟慮的設計會把一個系統分解為一群相互協作的同事物件,給每一個同事物件以獨特的責任,恰當的配置它們之間的協作關系,使它們可以在一起作業,
如同阿里開源的異構資料源離線同步工具--DataX,下圖是他的設計圖:

中介者模式的UML類圖如下:

如上圖所示,中介者模式涉及到四種角色:
- 抽象中介者(Mediator)角色:定義出同事物件到中介者物件的介面,其中主要的方法是一個(或者多個)事件方法,在有些情況下,這個抽象物件可以省略,一般而言,這個角色由一個Java抽象類或者Java物件實作,
- 具體調停者(ConcreteMediator)角色:從抽象中介者繼承而來,實作了抽象類所宣告的事件方法,具體中介者知曉所有的具體同事類,它從具體同事物件接收訊息、向具體同事物件發出命令,―般而言,這個角色由具體Java類實作,
- 抽象同事類(Colleague)角色:定義出中介者物件到同事物件的介面,同事物件只知道中介者而不知道其余的同事物件,一般而言,這個角色由一個Java抽象類或者Java物件實作,
- 具體同事類(ConcreteColleague)角色:所有的具體同事類均從抽象同事類繼承而來,每一個具體同事類都很清楚它自己在小范圍內的行為,而不知道它在大范圍內的目的;一般而言,這個角色由具體Java類實作,
智能家電的例子
在一個智能家電的系統中,包括鬧鐘、咖啡機、電視機、窗簾等家具組成,當主人要看電視時,各個設備可以協同作業,自動完成看電視的準備作業,比如:鬧鐘響起 --> 咖啡機打開做咖啡 --> 窗簾自動降下 --> 電視機開始播放;在這里就以這個為例子講解,
例子的UML類圖如下:

抽象中介者角色:
package com.charon.mediator;
/**
* @className: Mediator
* @description: 抽象中介者物件
* @author: charon
* @create: 2022-04-03 23:16
*/
public abstract class Mediator {
/**
* 將同事物件注冊到中介者類中
* @param colleagueName
* @param colleage
*/
abstract void register(String colleagueName, Colleague colleage);
/**
* 接收由具體的同事物件發出的訊息
* @param stateChange
* @param colleagueName
*/
abstract void getMessage(int stateChange,String colleagueName);
/**
* 發送訊息
*/
abstract void sendMessage();
}
具體中介者角色:
package com.charon.mediator;
import java.util.HashMap;
import java.util.Map;
/**
* @className: ConcreteMediator
* @description:
* @author: charon
* @create: 2022-04-03 23:26
*/
public class ConcreteMediator extends Mediator{
/**
* 用于存放所有的同事物件
*/
private Map<String,Colleague> colleagueMap;
private Map<String,String> interMap;
public ConcreteMediator() {
this.colleagueMap = new HashMap<>();
this.interMap = new HashMap<>();
}
@Override
void register(String colleagueName, Colleague colleage) {
colleagueMap.put(colleagueName,colleage);
if(colleage instanceof Alarm){
interMap.put("alarm",colleagueName);
}else if(colleage instanceof CoffeeMachine){
interMap.put("coffeeMachine",colleagueName);
}else if (colleage instanceof TV){
interMap.put("tv",colleagueName);
}else if (colleage instanceof Curtains){
interMap.put("curtains",colleagueName);
}
}
@Override
void getMessage(int state, String colleagueName) {
if (colleagueMap.get(colleagueName) instanceof Alarm){
if(state == 0){
((CoffeeMachine)colleagueMap.get(interMap.get("coffeeMachine"))).startCoffee();
((TV)colleagueMap.get(interMap.get("tv"))).startTv();
}else if(state == 1){
((TV)colleagueMap.get(interMap.get("tv"))).stopTv();
}
}else if(colleagueMap.get(colleagueName) instanceof CoffeeMachine){
((Curtains)colleagueMap.get(interMap.get("curtains"))).upCurtains();
}
}
@Override
void sendMessage() {
}
}
抽象同事角色:
package com.charon.mediator;
/**
* @className: Colleague
* @description:
* @author: charon
* @create: 2022-04-03 23:18
*/
public abstract class Colleague {
private Mediator mediator;
private String name;
public Colleague(Mediator mediator, String name) {
this.mediator = mediator;
this.name = name;
}
/**
* Gets the value of mediator
*
* @return the value of mediator
*/
public Mediator getMediator() {
return mediator;
}
/**
* Gets the value of name
*
* @return the value of name
*/
public String getName() {
return name;
}
abstract void sendMessage(int stateChange);
}
具體同事角色:
package com.charon.mediator;
/**
* @className: Curtains
* @description: 窗簾
* @author: charon
* @create: 2022-04-03 23:34
*/
public class Curtains extends Colleague{
@Override
void sendMessage(int stateChange) {
this.getMediator().getMessage(stateChange,this.getName());
}
public Curtains(Mediator mediator, String name) {
super(mediator, name);
mediator.register(name,this);
}
public void upCurtains(){
System.out.println("窗簾在上升,,,,");
}
public void downCurtains(){
System.out.println("窗簾在下降,,,,");
}
}
package com.charon.mediator;
/**
* @className: TV
* @description:
* @author: charon
* @create: 2022-04-03 23:33
*/
public class TV extends Colleague{
public TV(Mediator mediator, String name) {
super(mediator, name);
mediator.register(name, this);
}
@Override
void sendMessage(int stateChange) {
this.getMediator().getMessage(stateChange,this.getName());
}
public void startTv(){
System.out.println("電視機開機,,,");
}
public void stopTv(){
System.out.println("電視機關機,,,");
}
}
package com.charon.mediator;
/**
* @className: CoffeeMachine
* @description:
* @author: charon
* @create: 2022-04-03 23:32
*/
public class CoffeeMachine extends Colleague{
public CoffeeMachine(Mediator mediator, String name) {
super(mediator, name);
mediator.register(name,this);
}
@Override
void sendMessage(int stateChange) {
this.getMediator().getMessage(stateChange,this.getName());
}
public void startCoffee(){
System.out.println("咖啡機啟動,,,,");
}
public void stopCoffee(){
System.out.println("咖啡機關閉,,,,");
sendMessage(0);
}
}
package com.charon.mediator;
/**
* @className: Alarm
* @description:
* @author: charon
* @create: 2022-04-03 23:30
*/
public class Alarm extends Colleague{
public Alarm(Mediator mediator, String name) {
super(mediator, name);
mediator.register(name,this);
}
@Override
void sendMessage(int stateChange) {
this.getMediator().getMessage(stateChange,this.getName());
}
void sendAlarm(int statChange){
sendMessage(0);
}
}
客戶端測驗:
package com.charon.mediator;
/**
* @className: Client
* @description: http://c.biancheng.net/view/1393.html
* @author: charon
* @create: 2022-03-31 23:14
*/
public class Client {
public static void main(String[] args) {
Mediator mediator = new ConcreteMediator();
Alarm alarm = new Alarm(mediator, "alarm");
CoffeeMachine coffeeMachine = new CoffeeMachine(mediator, "coffeeMachine");
Curtains curtain = new Curtains(mediator, "curtain");
TV tv = new TV(mediator, "tv");
// 鬧鐘發出聲響
alarm.sendAlarm(0);
coffeeMachine.stopCoffee();
alarm.sendAlarm(1);
}
}
列印:
咖啡機啟動,,,,
電視機開機,,,
咖啡機關閉,,,,
窗簾在上升,,,,
咖啡機啟動,,,,
電視機開機,,,
中介者模式的主要優點如下:
- 類之間各司其職,符合迪米特法則
- 降低了物件之間的耦合性,使得物件易于獨立地被復用
- 將物件間的一對多關聯轉變為一對一的關聯,提高系統的靈活性,使得系統易于維護和擴展
其主要缺點是:
- 中介者模式降低了同事物件的復雜性,代價是增加了中介者類的復雜性
- 中介者類經常充滿了各個具體同事類的關系協調代碼,這種代碼常常是不能復用的,因此,具體同事類的復用是以中介者類的不可復用為代價的
- 中介者模式將原本多個物件直接的相互依賴變成了中介者和多個同事類的依賴關系,當同事類越多時,中介者就會越臃腫,變得復雜且難以維護
中介者模式的應用場景
- 當物件之間存在復雜的網狀結構關系而導致依賴關系混亂且難以復用時,
- 當想創建一個運行于多個類之間的物件,又不想生成新的子類時,
中介者模式與門面模式的區別
門面模式和中介者模式很相似,兩者均是用來給出一個底耦合度的系統,門面模式為一個子系統提供一個簡單的介面,其中訊息的傳送時單方向的,因為門面模式的客戶端只通過門面類向子系統發出訊息,而不是相反的情況,
中介者模式則是中介類與同事物件的相互作用是多方向的,
中介者模式與觀察者模式的區別
中介者模式與觀察者模式是功能相類似的設計模式,它們之間是相互競爭的關系,換言之,使用了其中一者往往意味著放棄另一者,觀察者模式通過引入觀察者物件和主題物件來達到將通信分散化的目的;而中介者模式則封裝了物件之間的通信,從而將通信集中到一個個中介物件中,
觀察者模式需要觀察者物件和主題物件的相互協作才能達到目的,而且一個觀察主題物件通常有幾個觀察者物件,而一個觀察者物件也可以同時觀察幾個主題物件,
由于觀察者模式將性能分散到幾個物件中,因此更容易達到復用的目的,但是由于每一次通信都涉及幾個物件,因此,使用觀察者模式的設計可能不容易讀懂,使用了中介者模式使得系統的通信都要經過這個中介者物件,在所涉及的同事物件數目不多的情況下,使用中介者模式的設計是比較容易懂的設計,
在觀察者模式中,觀察者與被觀察者是不同的角色;而在中介者模式中,所有的同事物件都扮演同樣的角色,
本文著作權歸Charon和博客園共有,原創文章,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利,轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/455619.html
標籤:其他
上一篇:創建型:四. 工廠方法模式
