前言
中介者模式聽名字就能想到也是一種為了解決耦合度的設計模式,其實中介者模式在結構上與觀察者、命令模式十分相像;而應用目的又與結構模式“門面模式”有些相似。但區別於命令模式的是大多數中介者角色對於客戶程序是透明的。當然造成這種區別的原因是由於他們要達到的目的不同。
中介者模式
概念介紹
中介者模式是指用一個中介對象來封裝一系列的對象交互。中介者使個對象不需要顯示的相互引用,從而使其耦合松散,而且可以獨立地改變它們之間的交互。簡單地說,將原來兩個直接引用或者依賴的對象拆開,在中間加入一個“中介”對象,使得兩頭的對象分別與“中介”對象引用或者依賴。
例如下面這個結構,如果每個元素兩兩之間要產生聯系,關系就會變得錯綜復雜。
但是加了中介者之后,相互之間就可以解耦了。變成如下的關系結構。
舉例
和二跟老紀都是朝廷大臣,但是互相看不順眼,在皇上面前和和氣氣,背地里各自互相參對方。當然有時候皇上頒布旨意時讓兩個大臣一起合作去完成任務,他們也會相互合作的。和二跟老紀都想收拾對方,但是奈何雙方官職不相上下,所以當想收拾對方時就會通過皇上來實現,這個時候我們就當皇上理解為中介者(感覺有點牽強,就這樣吧😂)。下面用代碼來實現這個過程。
官員抽象類
/** * 官員(大臣)抽象類 */ public abstract class Official { protected Monarch monarch; /** * 每個官員必然要與君主有聯系 * @param monarch */ public Official(Monarch monarch){ this.monarch = monarch; } /** * 在抽象官員類中添加與中介者取得聯系的方法 * @param monarch */ public void setMonarch(Monarch monarch){ this.monarch = monarch; } }
君主抽象類
/** * 君主抽象類 */ public abstract class Monarch { /** * 君主保持着和各個官員的聯系 */ protected ConcurrentHashMap<String,Official> officials = new ConcurrentHashMap<>(); /** * 錄用官員 * @param name * @param official */ public void addOfficial(String name,Official official){ this.officials.put(name,official); } /** * 將官員革職查辦 * @param name */ public void removeOfficial(String name){ this.officials.remove(name); } /** * 處理各個官員之間的互相參奏的折子 * @param name * @param method */ public abstract void execute(String name,String method); }
老紀
/** * 老紀 */ public class LaoJi extends Official{ /** * 每個官員必然要與君主有聯系 * * @param monarch */ public LaoJi(Monarch monarch) { super(monarch); } /** * 做好本職工作 */ public void self(){ System.out.println("啟奏皇上,臣老紀參與編寫的四庫全書已經完成。"); } /** * 參其他官員或與其他官員合作 */ public void out(){ System.out.println("啟奏皇上,臣老紀要參和二一本,秀女選拔工作到現在還沒完成,理應當革職查辦。"); super.monarch.execute("heEr","self"); } }
和二
/** * 和二 */ public class HeEr extends Official { /** * 每個官員必然要與君主有聯系 * * @param monarch */ public HeEr(Monarch monarch) { super(monarch); } /** * 做好本職工作 */ public void self(){ System.out.println("啟奏皇上,臣和二掌管的秀女選拔工作已經完成。"); } /** * 參其他官員或與其他官員合作 */ public void out(){ System.out.println("啟奏皇上,臣和二要參老紀一本,四庫全書到目前還沒編寫完成,理應問斬。"); super.monarch.execute("laoji","self"); } }
黃三(乾隆皇上)
/** * 黃三(皇上) */ public class HuangSan extends Monarch { /** * 處理各個官員之間的互相參奏的折子 * * @param name * @param method */ @Override public void execute(String name, String method) { //做好自己份內的事情 if("self".equals(method)){ if("laoji".equals(name)){ ((LaoJi)super.officials.get(name)).self(); }else { ((HeEr)super.officials.get(name)).self(); } //我要參別人一本 }else { if("laoji".equals(name)){ ((LaoJi)super.officials.get(name)).out(); }else { ((LaoJi)super.officials.get(name)).out(); } } } }
測試類
public class Client { public static void main(String[] args) { //創建一個君主 Monarch monarch = new HuangSan(); //創建兩個官員 LaoJi laoJi = new LaoJi(monarch); HeEr heEr = new HeEr(monarch); //君主和兩個官員建立關系 monarch.addOfficial("laoji",laoJi); monarch.addOfficial("heEr",heEr); //有本奏上,無本退朝。 //laoJi.self(); laoJi.out(); System.out.println("---------------啟奏完畢"); //heEr.self(); heEr.out(); System.out.println("---------------啟奏完畢"); } }
運行結果
啟奏皇上,臣老紀要參和二一本,秀女選拔工作到現在還沒完成,理應當革職查辦。 啟奏皇上,臣和二掌管的秀女選拔工作已經完成。 ---------------啟奏完畢 啟奏皇上,臣和二要參老紀一本,四庫全書到目前還沒編寫完成,理應問斬。 啟奏皇上,臣老紀參與編寫的四庫全書已經完成。 ---------------啟奏完畢
上面的這個例子就是實現了中介者模式,皇上成了老紀跟和二的中介者。這樣使得兩位大臣也不用直接互懟了,除了干好自己的本職工作還可以督促其他同事完成工作。
迭代器模式的結構
中介者模式的組成角色如下所示
抽象中介者(Mediator)角色:抽象中介者角色定義統一的接口,用於各同事角色之間的通信。上面例子中君主類代表的就是這個角色。
具體中介者(ConcreteMediator)角色:具體中介者角色通過協調各同事角色,實現協作行為,為此它要指導並引用各個同事角色。上面例子中皇上代表的就是這個角色。
同事(Colleague)角色:每一個同事角色都知道對應的具體中介者角色,而且與其他的同事角色通信的時候,一定要通過中介者角色協作。上面的例子中老紀跟和二就是代表的這個角色。
總結
中介者模式將一個網狀的系統結構變成一個以中介者對象為中心的星形結構,在這個星型結構中,使用中介者對象與其他對象的一對多關系來取代原有對象之間的多對多關系。
優點
1、中介者模式簡化了對象之間的交互,它用中介者和同事的一對多交互代替了原來同事之間的多對多交互,一對多關系更容易理解、維護擴展,將原本難以理解的網狀結構轉換成相對簡單的星型結構。
2、中介者模式可將各同事對象解耦。中介者有利於各同事之間的松耦合,我們可以獨立的改變和復用每一個同事和中介者,增加新的中介者和新的同事類都比較方便,更好的符合“開閉原則”。
3、可以減少子類生成,中介者將原本分布於多個對象間的行為集中在一起,改變這些行為只需生成新的中介者子類即可,這使得各個同事類可被重用,無須對同事類進行擴展。
缺點
在具體中介者類中包含了大量同事之間的交互細節,可能會導致具體中介者類非常復雜,使得系統難以維護。
適用場景
1、系統中對象之間存在復雜的引用關系,系統結構混亂且難以理解。
2、 一個對象由於引用了其他很多對象並且直接和這些對象通信,導致難以復用該對象。
3、想通過一個中間類來封裝多個類中的行為,而又不想生成太多的子類。可以通過引入中介者類來實現,在中介者中定義對象交互的公共行為,如果需要改變行為則可以增加新的具體中介者類。
想了解更多的設計模式請查看Java設計模式學習記錄-GoF設計模式概述。