目錄
一、爲什麼要用中介者模式
中介者模式核心在於中介者這個角色,理解上可以參考現實中的中介者,中介就跟中間人一樣,跟橋樑一樣。比方說你到了個陌生的城市,要找工作,要找房子。如果一個人冒冒失失的盲目的找,不僅花費的時間跟精力非常大,即使找到了也不是理想中的。這時候中介就發揮作用了。它會根據你的要求,幫你安排那樣的工作適合你,跟用人方取得聯繫。
代碼的世界裏,如果各個類之間互相依賴,每個類內部引入其他類,當類增多時就會形成網狀依賴關係(下圖左),這時代碼的耦合度就很高;中介者模式可以很好的解耦這種依賴關係,所有類都只和中介者有關聯,形成一種星狀結構(下圖右),通過中介者建立聯繫,而彼此不需要知道對方是誰,彼此獨立,耦合性很低。
說道這你肯定想起了Spring, Spring的一個主要功能就是IOC,各層間、層內不同對象也是不需要事先注入綁定,而是將創建bean的事情全交給Spring處理,Spring負責各方的聯繫。
中介者模式是迪米特原則的經典體現:迪米特法則(Law of Demeter)又叫作最少知識原則(Least Knowledge Principle 簡寫LKP),它要求一個對象應該對其他對象保持最少的瞭解。如果兩個類不必彼此直接通信,那麼這兩個類就不應當發生直接的相互作用。如果其中的一個類需要調用另一個類的某一個方法的話,可以通過第三者轉發這個調用。
二、中介者模式中的角色
中介者模式涉及到的角色有四個:
- 抽象中介者角色:抽象中介者角色定義統一的接口,以及一個或者多個事件方法,用於各同事角色之間的通信。
- 具體中介者角色:實現了抽象中介者所聲明的事件方法,協調各同事類之間的行爲,持有所有同事類對象的引用。
- 抽象同事類角色:定義了抽象同事類,持有抽象中介者對象的引用。
- 具體同事類角色:繼承抽象同事類,實現自己業務,通過中介者跟其他同事類進行通信。
三、中介者模式怎麼用?
我們實現下面的一個實例:
比如模擬李雲龍打仗。李雲龍現在要去打鬼子的伏擊搶點彈藥回來,手底下有3個營,鬼子裝備精良,這三個營之間只有互相配合纔有勝算。那李雲龍就是指揮官(中介者),三個營(同事類)完成各自任務,相互間通信配合都通過李雲龍。
抽象同事類:
public interface Colleague {
void battle();
void teamWork();
}
具體同事類:一營
/**
* Feng, Ge 2020/3/10 0010 15:02
*/
public class FirstCamp implements Colleague {
private Mediator mediator;
public FirstCamp(Mediator mediator) {
this.mediator = mediator;
mediator.receive("一營", this);
}
@Override
public void battle() {
System.out.println("一營要正面進攻了!");
}
@Override
public void teamWork() {
System.out.println("報告營長,一營任務正面扛不住了,請求李團長派三營接應!");
mediator.order("三營");
}
}
具體同事類:二營
/**
* Feng, Ge 2020/3/10 0010 15:02
*/
public class SecondCamp implements Colleague {
private Mediator mediator;
public SecondCamp(Mediator mediator) {
this.mediator = mediator;
mediator.receive("二營", this);
}
@Override
public void battle() {
System.out.println("二營要側面進攻了!");
}
@Override
public void teamWork() {
System.out.println("報告營長,二營側面進攻有些壓力,需要一營正面加強火力掩護!");
mediator.order("一營");
}
}
具體同事類:三營
/**
* Feng, Ge 2020/3/10 0010 15:03
*/
public class ThirdCamp implements Colleague {
private Mediator mediator;
public ThirdCamp(Mediator mediator) {
this.mediator = mediator;
mediator.receive("三營", this);
}
@Override
public void battle() {
System.out.println("三營在外圍接應!");
}
@Override
public void teamWork() {
System.out.println("報告營長,三營任務已完成,請指示!");
}
}
抽象中介者:
public interface Mediator {
// 各營在這裏註冊,接收各營發來的戰況電報
void receive(String name, Colleague colleague);
// 下達命令
void order(String name);
}
具體中介者: 李雲龍
/**
* Feng, Ge 2020/3/10 0010 14:51
*/
public class YunLongLi implements Mediator {
private Map<String,Colleague> map = new HashMap<String , Colleague>();
@Override
public void receive(String name, Colleague colleague) {
map.put(name, colleague);
}
@Override
public void order(String name) {
map.get(name).battle();
}
}
測試類:
/**
* Feng, Ge 2020/3/10 0010 15:49
*/
public class MdiatorTest {
public static void main(String[] args) {
Mediator mediator = new YunLongLi();
FirstCamp firstCamp = new FirstCamp(mediator);
SecondCamp secondCamp = new SecondCamp(mediator);
ThirdCamp thirdCamp = new ThirdCamp(mediator);
firstCamp.battle();
firstCamp.teamWork();
System.out.println("====================================");
secondCamp.battle();
secondCamp.teamWork();
System.out.println("====================================");
thirdCamp.battle();
thirdCamp.teamWork();
System.out.println("把老子的意大利炮來出來,轟他孃的小鬼子,秀琴對不住了,開炮!!!!!");
}
}
結果:
一營要正面進攻了!
報告營長,一營任務正面扛不住了,請求李團長派三營接應!
三營在外圍接應!
====================================
二營要側面進攻了!
報告營長,二營側面進攻有些壓力,需要一營正面加強火力掩護!
一營要正面進攻了!
====================================
三營在外圍接應!
報告營長,三營任務已完成,請指示!
把老子的意大利炮來出來,轟他孃的小鬼子,秀琴對不住了,開炮!!!!!
以上,各營的行動彼此需要支援的時候,例如一營需要三營外圍接應的時候,不是一營長和三營長直接對話,而是通過李雲龍,李雲龍根據name去調用具體的map.get(name).battle()方法。
四、中介者模式的優缺點
優點
1)解耦。把同事類原來一對多的依賴變成一對一的依賴,降低同事類的耦合度,同時也符合了迪米特原則。
缺點
1)中介者模式把業務流程和協調都寫在中介者,當同事類越多,中介者的業務就越複雜,造成不好管理的弊端。
2)中介者模式還有一個明顯的缺點,如果要增減同事類,必須得修改抽象中介者角色和具體中介者角色類。
中介者模式和代理模式的區別:
代理模式在不改變目標類的基礎上增強目標類功能,目標類是隱藏的,不讓別人知道具體的操作細節,而中介者模式則主要用戶多對象多對多的複雜交互,降低耦合。