基本需求
- 智慧家庭包括各種裝置,鬧鐘、咖啡機、電視機、窗簾等
- 要看電視時,各個裝置可以協同工作,自動完成看電視的準備工作,比如流程為:鬧鈴響起->咖啡機開始做咖啡->窗簾自動落下->電視機開始播放
傳統方案
- 各個類之間相互呼叫,依賴嚴重,訊息傳遞不準確,呼叫結構混亂
- 說明
- 當各電器物件有多種狀態改變時,相互之間的呼叫關係會比較複雜
- 各個 電器物件彼此聯絡,你中有我,我中有你,不利於鬆耦合
- 各個電器物件之間所傳遞的訊息(引數),容易混亂
- 當系統增加一個新的電器物件時,或者執行流程改變時,程式碼的可維護性、擴充套件性都不理想 考慮中介者模式
基本介紹
-
中介者模式(Mediator),用一箇中介物件來封裝一系列的物件互動。中介者使各個物件不需要顯式地相互引用,從而使其耦合鬆散,而且可以獨立地改變它們之間的互動
-
中介者模式屬於行為型模式,使程式碼易於維護
-
比如MVC模式,C(Controller 控制器)是M(Model 模型)和V(View 檢視)的中介者,在前後端互動時起到了中間人的作用
-
比如租房子
- 沒有中介:有六個房東需要出租房屋,適合不一樣的人租住。這六個房東之間有點聯絡。這時租客來租房,看了一號房東的房子不滿意、但是一號房東覺得可以讓他去看看其他五個朋友的房間。然後開始聯絡五個朋友。進行訊息傳遞。一個如此,另外五個亦如此,如果二號房東房屋不出租或者出租出去了,情況發生了變化。他則需要通知其他五個朋友,告訴他們不用再給他介紹租客。這裡就造成了中間一個人發生了變化,需要改動其他五個人
- 有中介:那六個房東都把房屋交給中介處理。租客A看房間一不滿意直接通過中介看房間二。當房間二被出租了。中介也只需要通知房東二號、然後他們簽訂合同。下次還有人看房間就不會再看房間二。這裡一個出現了變化也就影響改變了一個。並不會影響其他另外五個房東
-
UML類圖(原理)
- 說明
- Mediator 就是抽象中介者,定義了同事物件到中介者物件的介面
- Colleague 是抽象同事類
- ConcreteMediator 具體的中介者物件, 實現抽象方法, 他需要知道所有的具體的同事類,即以一個集合來管理HashMap,並接受某個同事物件訊息,完成相應的任務
- ConcreteColleague 具體的同事類,會有很多, 每個同事只知道自己的行為,而不瞭解其他同事類的行為(方法),但是他們都依賴中介者物件
- 說明
-
UML類圖(案例)
- 說明
- ConcreteMediator是中介者實現類
- 在建立同事實現類的時候通過其構造方法將其註冊到中介者中,通過sendMessage方法向中介者傳送訊息
- ConcreteMediator的getMessage方法會接收到同事類的訊息協調呼叫其他物件,是核心方法
- 說明
-
程式碼實現
-
public abstract class Mediator { // 中介者抽象類 // 將同事類加入到中介者中,由中介者對所有同事類進行互動,同事類之間不進行互動 // 將依賴由網狀變成星狀 public abstract void register(String colleagueName, Colleague colleague); // 接收訊息 由同事類發出 public abstract void getMessage(String colleagueName, int stateChange); // 傳送訊息,發給同事類,本次案例中沒有用到 public abstract void sendMessage(); } // 中介者實現類 public class ConcreteMediator extends Mediator { // 使用集合管理所有的中介者,如果key重複,則是最新註冊的 ,可否弄成MapList的形式管理重複key private Map<String, Colleague> colleagueMap; // 名稱的集合,方便我們自己獲取對應的同事類,因為每次註冊時 我們並不知道key,想獲取value時不能獲取,指定名稱 後續使用簡單 private Map<String, String> nameMap; public ConcreteMediator() { this.colleagueMap = new HashMap<>(); this.nameMap = new HashMap<>(); } @Override public void register(String colleagueName, Colleague colleague) { colleagueMap.put(colleagueName, colleague); if (colleague instanceof Alarm) { // 自定義名稱 方便我們下面使用 nameMap.put("alarm", colleagueName); } else if (colleague instanceof CoffeeMachine) { nameMap.put("coffeeMachine", colleagueName); } else if (colleague instanceof Curtain) { nameMap.put("curtain", colleagueName); } else if (colleague instanceof TV) { nameMap.put("tv", colleagueName); } } @Override public void getMessage(String colleagueName, int stateChange) { // 根據得到訊息,完成對應任務,中介者在這個方法,協調各個具體的同事物件,完成任務 if (colleagueMap.get(colleagueName) instanceof Alarm) { // 處理鬧鐘的訊息 可使用中介者的sendMessage方法進行處理 if (stateChange == 0) { ((CoffeeMachine) colleagueMap.get(nameMap.get("coffeeMachine"))).startCoffee(); ((TV) colleagueMap.get(nameMap.get("tv"))).startTv(); } else if (stateChange == 1) { ((TV) colleagueMap.get(nameMap.get("tv"))).stopTv(); } } else if (colleagueMap.get(colleagueName) instanceof CoffeeMachine) { // 處理咖啡機的訊息 if (stateChange == 0) { ((Curtain) colleagueMap.get(nameMap.get("curtain"))).upCurtains(); } } else if (colleagueMap.get(colleagueName) instanceof Curtain) { // 處理窗簾的訊息 System.out.println(); } else if (colleagueMap.get(colleagueName) instanceof TV) { // 處理電視機的訊息 System.out.println(); } } @Override public void sendMessage() { } }
-
public abstract class Colleague { // 同事抽象類 protected String name; private Mediator mediator; public Colleague(String name, Mediator mediator) { this.name = name; this.mediator = mediator; } public Mediator getMediator() { return this.mediator; } // 傳送訊息 public abstract void sendMessage(int stateChange); } // 同事子類一 鬧鐘類 public class Alarm extends Colleague { public Alarm(String name, Mediator mediator) { super(name, mediator); // 將自己在中介者中進行註冊 mediator.register(name, this); } @Override public void sendMessage(int stateChange) { // 獲取中介者 呼叫中介者的getMessage方法 將訊息傳遞給中介者 由中介者處理訊息 this.getMediator().getMessage(super.name, stateChange); } public void sendAlarm(int stateChange) { sendMessage(stateChange); } } // 同事子類二 咖啡機 public class CoffeeMachine extends Colleague { public CoffeeMachine(String name, Mediator mediator) { super(name, mediator); mediator.register(name, this); } @Override public void sendMessage(int stateChange) { this.getMediator().getMessage(super.name, stateChange); } public void startCoffee() { System.out.println("It's time to startcoffee!"); } public void finishCoffee() { System.out.println("After 5 minutes!"); System.out.println("Coffee is ok!"); sendMessage(0); } } // 同事子類三 窗簾 public class Curtain extends Colleague { public Curtain(String name, Mediator mediator) { super(name, mediator); mediator.register(name, this); } @Override public void sendMessage(int stateChange) { this.getMediator().getMessage(super.name, stateChange); } public void upCurtains() { System.out.println("I am holding Up Curtains!"); } } // 同事子類四 電視機 public class TV extends Colleague { public TV(String name, Mediator mediator) { super(name, mediator); mediator.register(name, this); } @Override public void sendMessage(int stateChange) { this.getMediator().getMessage(super.name, stateChange); } public void startTv() { System.out.println("It's time to StartTv!"); } public void stopTv() { System.out.println("Stop Tv!"); } }
-
public class Client { public static void main(String[] args) { // 建立中介者 Mediator concreteMediator = new ConcreteMediator(); // 建立同事類 並將其註冊到中介者中 Alarm alarm = new Alarm("alarm", concreteMediator); CoffeeMachine coffeeMachine = new CoffeeMachine("coffeeMachine", concreteMediator); Curtain curtain = new Curtain("curtain", concreteMediator); // 注意 此處中介者中的nameMap就起到了作用 我們的名稱是TV,而我們中介中使用的tv作為key使用 沒有nameMap就會報錯 nameMap起到橋樑作用 TV tv = new TV("TV", concreteMediator); // 使用alarm傳送訊息 alarm.sendAlarm(0); coffeeMachine.finishCoffee(); alarm.sendAlarm(1); } }
-
注意事項
- 多個類相互耦合,會形成網狀結構, 使用中介者模式將網狀結構分離為星型結構,進行解耦
- 如果增加一個同事類,直接增加即可,降低了類的複雜度,將一對多轉化成了一對一
- 減少類間依賴,降低了耦合,符合迪米特原則
- 中介者承擔了較多的責任,一旦中介者出現了問題,整個系統就會受到影響
- 中介者 承擔了較多的責任,一旦中介者出現了問題,整個系統就會受到影響