【設計模式從入門到精通】17-中介者模式
阿新 • • 發佈:2022-01-12
中介者模式
目錄
中介者模式
1、智慧家庭管理問題
智慧家庭專案:
-
1)智慧家庭包括各種裝置,鬧鐘、咖啡機、電視機、窗簾等
-
2)主人要看電視時,各個裝置可以協同工作,自動完成看電視的準備工作,比如流程為:
鬧鈴響起 => 咖啡機開始做咖啡 => 窗簾自動落下 => 電視機開始播放
傳統方案解決智慧家庭管理問題
傳統方式問題分析
- 1)當各電器物件有多種狀態改變時,相互之間的呼叫關係會比較複雜
- 2)各個電器物件彼此聯絡,你中有我,我中有你,不利於鬆耦合
- 3)各個電器物件之間所傳遞的訊息(引數),容易混亂
- 4)當系統增加一個新的電器物件時,或者執行流程改變時,程式碼的可維護性、擴充套件性都不理想→考慮中介者模式
2、中介者模式
- 1)中介者模式(
Mediator Pattern
),用一箇中介物件來封裝一系列的物件互動。中介者使各個物件不需要顯式地相互引用,從而使其耦合鬆散,而且可以獨立地改變它們之間的互動 - 2)中介者模式屬於行為型模式,使程式碼易於維護
- 3)比如 MVC 模式,C(
Controller
控制器)是M(Model
模型)和V(View
檢視)的中介者,在前後端互動時起到了中間人的作用
原理類圖
中介者模式角色及職責
Mediator
ConcreteMediator
【具體的中介者物件】:實現抽象中介者方法,需要知道所有具體的同事類,即以一個集合來管理HashMap
,並接受某個同事物件訊息,完成相應的任務Colleague
【抽象同事類】ConcreteColleague
【具體的同事類】:會有很多,只知道自己的行為,而不瞭解其他同事類的行為(方法),但他們都依賴中介者物件
3、中介者模式解決智慧家庭管理問題
UML 類圖
智慧家庭管理操作流程
- 1)建立
ConcreMediator
物件 - 2)建立各個同事類物件,比如:
Alarm
、CoffeeMachine
、TV
... - 3)在建立同事類物件時,直接通過構造器加入到
colleagueMap
- 4)同事類物件可以呼叫
sendMessage
,最終會去呼叫ConcreteMediator
的getMessage
方法 - 5)
getMessage
會根據接收到的同事物件發出的訊息,來協調呼叫其它的同事物件,完成任務 - 6)可以看到
getMessage
是核心方法,完成相應任務
核心程式碼
抽象中介者
public abstract class Mediator {
public abstract void registerColleague(Colleague colleague);
public abstract void getMsg(Integer state, String name);
public abstract void sendMsg();
}
抽象同事類
public abstract class Colleague {
private Mediator mediator;
public Colleague(Mediator mediator) {
this.mediator = mediator;
}
public Mediator getMediator() {
return this.mediator;
}
public void sendMsg(Integer state) {
this.getMediator().getMsg(state, this.getClass().getSimpleName());
}
}
具體同事類
/**
* 鬧鐘
*/
public class Alarm extends Colleague {
public Alarm(Mediator mediator) {
super(mediator);
this.getMediator().registerColleague(this);
}
/**
* 鬧鈴響起
*/
public void openAlarm() {
System.out.println(">>>鬧鈴響起");
try {
//模擬鬧鈴耗時
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
sendMsg(1);
}
/**
* 鬧鈴關閉
*/
public void closeAlarm() {
System.out.println(">>>鬧鈴關閉");
sendMsg(0);
}
}
/**
* 咖啡機
*/
public class CoffeeMachine extends Colleague {
public CoffeeMachine(Mediator mediator) {
super(mediator);
this.getMediator().registerColleague(this);
}
/**
* 煮咖啡
*/
public void makeCoffee() {
System.out.println(">>>煮咖啡中...");
sendMsg(0);
try {
//模擬煮咖啡耗時
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 煮咖啡完畢
*/
public void completeCoffee() {
System.out.println(">>>咖啡已煮好");
sendMsg(1);
}
}
/**
* 窗簾
*/
public class Curtain extends Colleague {
public Curtain(Mediator mediator) {
super(mediator);
this.getMediator().registerColleague(this);
}
/**
* 拉起窗簾
*/
public void upCurtain() {
System.out.println(">>>拉起窗簾...");
sendMsg(1);
try {
//模擬拉起窗簾耗時
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 拉下窗簾
*/
public void downCurtain() {
System.out.println(">>>拉下窗簾...");
sendMsg(0);
try {
//模擬拉下窗簾耗時
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 電視機
*/
public class TV extends Colleague {
public TV(Mediator mediator) {
super(mediator);
this.getMediator().registerColleague(this);
}
/**
* 開啟電視
*/
public void openTV() {
System.out.println(">>>開啟電視...");
sendMsg(1);
}
/**
* 關閉電視
*/
public void closeTV() {
System.out.println(">>>關閉電視...");
sendMsg(0);
}
/**
* 切換頻道
*/
public void switchChannel(Integer state) {
System.out.println(">>>切換頻道:" + state);
sendMsg(state);
try {
//模擬看電視耗時
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
具體中介者
public class ConcreteMediator extends Mediator {
private Map<String, Colleague> colleagueMap;
public ConcreteMediator() {
this.colleagueMap = new HashMap<>();
}
@Override
public void registerColleague(Colleague colleague) {
colleagueMap.put(colleague.getClass().getSimpleName(), colleague);
}
@Override
public void getMsg(Integer state, String name) {
Colleague colleague = colleagueMap.get(name);
if (colleague instanceof Alarm) {
dealAlarm(state);
} else if (colleague instanceof CoffeeMachine) {
dealCoffeeMachine(state);
} else if (colleague instanceof Curtain) {
dealCurtain(state);
} else if (colleague instanceof TV) {
dealTV(state);
}
}
/**
* 鬧鈴響起後操作
*
* @param state
*/
private void dealAlarm(Integer state) {
if (Integer.valueOf(1).equals(state)) {
((Alarm) colleagueMap.get(Alarm.class.getSimpleName())).closeAlarm();
((CoffeeMachine) colleagueMap.get(CoffeeMachine.class.getSimpleName())).makeCoffee();
}
}
/**
* 咖啡機煮咖啡完畢後操作
*
* @param state
*/
private void dealCoffeeMachine(Integer state) {
if (Integer.valueOf(1).equals(state)) {
((Curtain) colleagueMap.get(Curtain.class.getSimpleName())).downCurtain();
}
}
/**
* 窗簾落下後操作
*
* @param state
*/
private void dealCurtain(Integer state) {
if (Integer.valueOf(0).equals(state)) {
TV tv = (TV) colleagueMap.get(TV.class.getSimpleName());
tv.openTV();
tv.switchChannel(101);
}
}
/**
* 電視關閉後操作
*
* @param state
*/
private void dealTV(Integer state) {
if (Integer.valueOf(0).equals(state)) {
((Curtain) colleagueMap.get(Curtain.class.getSimpleName())).upCurtain();
}
}
@Override
public void sendMsg() {
// Do Nothing...
}
}
測試程式碼
//建立中介者
Mediator mediator = new ConcreteMediator();
//建立各個同事類,並加入Mediator中介者的Map物件中
Alarm alarm = new Alarm(mediator);
CoffeeMachine coffeeMachine = new CoffeeMachine(mediator);
Curtain curtain = new Curtain(mediator);
TV tv = new TV(mediator);
//鬧鐘響起
alarm.openAlarm();
coffeeMachine.completeCoffee();
tv.closeTV();
//>>>鬧鈴響起
//>>>鬧鈴關閉
//>>>煮咖啡中...
//>>>咖啡已煮好
//>>>拉下窗簾...
//>>>開啟電視...
//>>>切換頻道:101
//>>>關閉電視...
//>>>拉起窗簾...
4、中介者模式的注意事項和細節
優點
-
1)多個類相互耦合,會形成網狀結構,使用中介者模式將網狀結構分離為星型結構,進行解耦
-
2)減少類間依賴,降低了耦合,符合迪米特原則
缺點
-
3)中介者承擔了較多的責任,一旦中介者出現了問題,整個系統就會受到影響
-
4)如果設計不當,中介者物件本身變得過於複雜,這點在實際使用時,要特別注意