摘要:那在我們的程序設計中有沒有這樣的模式有的,中介者模式應運而生,目的就是處理這樣的情景問題。最后來看客戶端的實現(xiàn),代碼如下被攻打,請求支援可以看到,表面上請求還是從發(fā)出,但是已經委托了中介者進行業(yè)務邏輯和流程的處理。
本篇文章已授權微信公眾號 guolin_blog (郭霖)獨家發(fā)布
小時候鐘愛戰(zhàn)爭片,《地道戰(zhàn)》、《雞毛信》、《鐵道游擊隊》一系列的老電影,咦~想起都激動得起雞皮疙瘩。不過覺得特別逗的是,電影里面總會有“這里是xxx,我們被包圍了,請求支援請求支援”這么一句臺詞。
來分析一下這句臺詞怎么來的。假設有N多個戰(zhàn)區(qū),戰(zhàn)區(qū)的分布錯綜復雜,很多時候一個戰(zhàn)區(qū)的丟失會影響整個戰(zhàn)爭局勢。所以這就得要有一個司令部指揮和協(xié)調各個戰(zhàn)區(qū),而一旦戰(zhàn)區(qū)被攻打,報告司令部請求支援,司令部則調度其他戰(zhàn)區(qū)進行協(xié)助。
那在我們的程序設計中有沒有這樣的模式?有的,中介者模式應運而生,目的就是處理這樣的情景問題。
一、中介者模式 定義??中介者封裝一系列對象相互作用,使得這些對象耦合松散,并且可以獨立的改變它們之間的交互。
UML中介者模式涉及到的角色有四個:
- 抽象中介者角色:抽象中介者角色定義統(tǒng)一的接口,以及一個或者多個事件方法,用于各同事角色之間的通信。
- 具體中介者角色:實現(xiàn)了抽象中介者所聲明的事件方法,協(xié)調各同事類之間的行為,持有所有同事類對象的引用。
- 抽象同事類角色:定義了抽象同事類,持有抽象中介者對象的引用。
- 具體同事類角色:繼承抽象同事類,實現(xiàn)自己業(yè)務,通過中介者跟其他同事類進行通信。
二、中介者模式實戰(zhàn)假設這樣的一個情景。有A、B、C三個戰(zhàn)區(qū),A被敵方攻打,請求B支援。但是此時B也被敵方攻打,所以A繼續(xù)向C請求支援,這么巧C此時正在支援B。情景比較簡單,我們的例子也圍繞著這個情景來展開,首先來看不使用中介者模式是怎么實現(xiàn)的。
A戰(zhàn)區(qū)代碼如下:
public class SituationA { // 請求支援 public void requestSupport(String situation) { System.out.println(getClass().getSimpleName() + ":這里是A戰(zhàn)區(qū),現(xiàn)在被敵方攻打,請求" + situation + "支援"); } }
SituationA定義了請求支援的方法,向其他戰(zhàn)區(qū)請求支援。再來看B戰(zhàn)區(qū)的代碼定義:
public class SituationB { // 請求支援 public void requestSupport(String situation) { System.out.println(getClass().getSimpleName() + ":這里是B戰(zhàn)區(qū),現(xiàn)在被敵方攻打,請求" + situation + "支援"); } // 是否支援 public void support(boolean isSupport) { if (isSupport) { System.out.println(getClass().getSimpleName() + ":Copy that,還有五秒鐘到達戰(zhàn)場"); } else { System.out.println(getClass().getSimpleName() + ":支援你妹,我也正在被攻打"); } } }
SituationB也定義了請求支援的方法,還多了根據(jù)isSupport是否支援其他戰(zhàn)區(qū)的方法。還有SituationC,SituationC和SituationB代碼差不多,直接貼出來了,不多做解釋。
public class SituationC { // 請求支援 public void requestSupport(String situation) { System.out.println(getClass().getSimpleName() + ":這里是B戰(zhàn)區(qū),現(xiàn)在被敵方攻打,請求" + situation + "支援"); } // 是否支援 public void support(boolean isSupport) { if (isSupport) { System.out.println(getClass().getSimpleName() + ":Copy that,還有五秒鐘到達戰(zhàn)場"); } else { System.out.println(getClass().getSimpleName() + ":不好意思,來遲一步了,正在前往別的戰(zhàn)區(qū)支援"); } } }
OK,三個類都定義好了,我們根據(jù)情景看看客戶端是怎樣運行的,代碼如下:
public class Client { public static void main(String[] args) { System.out.println("-------A被攻打,請求B支援--------"); SituationA situationA = new SituationA(); situationA.requestSupport("B"); System.out.println("-------B也正在被攻打--------"); SituationB situationB = new SituationB(); situationB.support(false); System.out.println("-------A又向C請求支援--------"); situationA.requestSupport("C"); System.out.println("-------C很忙--------"); SituationC situationC = new SituationC(); situationC.support(false); } }
運行結果如下:
-------A被攻打,請求B支援--------
SituationA:這里是A戰(zhàn)區(qū),現(xiàn)在被敵方攻打,請求B支援
-------B也正在被攻打--------
SituationB:支援你妹,我也正在被攻打
-------A又向C請求支援--------
SituationA:這里是A戰(zhàn)區(qū),現(xiàn)在被敵方攻打,請求C支援
-------C很忙--------
SituationC:不好意思,來遲一步了,正在前往別的戰(zhàn)區(qū)支援
回到我們的場景當中,A、B、C是相互兩兩關聯(lián)的,并且關聯(lián)的兩個類與其他類是不能協(xié)調通信。因此,在實際中,戰(zhàn)區(qū)類增多,它們之間的耦合度越高,這樣首先會造成當一個類修改了,其他類也要跟著需要修改,然后就是多個類之間的通信變得復雜混亂。就跟我們上面列子一樣,A、B、C相互支援,A并不知道C已經支援B了。因為這些原因,在代碼設計中加入中介者角色,每個類都經過中介者進行溝通和協(xié)調。
下面來看中介者模式的實現(xiàn),首先定義抽象中介者角色類,代碼如下:
public abstract class Mediator { protected SituationA situationA; protected SituationB situationB; protected SituationC situationC; Mediator() { situationA = new SituationA(this); situationB = new SituationB(this); situationC = new SituationC(this); } /** * 事件的業(yè)務流程處理 * * @param method */ public abstract void execute(String method); }
抽象中介者類主要定義了同事類的事件業(yè)務流程方法,并且持有每一個具體同事類的引用,再來看具體中介者的實現(xiàn):
public class Command extends Mediator { public void execute(String method) { if (method.equals("aRequestSupport")) { this.aRequestSupport(); } else if (method.equals("bRequestSupport")) { this.bRequestSupport(); } } // A請求支援 private void aRequestSupport() { System.out.println("SituationA:這里是A戰(zhàn)區(qū),現(xiàn)在被敵方攻打,請求支援"); boolean isBSupport = isSupport(); // B是否可以支援 super.situationB.bSupport(isBSupport); if (!isBSupport) { // B支援不了,請求C System.out.println("-------A又向C請求支援--------"); boolean isASupport = isSupport(); // B是否可以支援 super.situationC.cSupport(isASupport); if (!isASupport) { System.out.println("-------自己看著辦吧。--------"); } } } // B請求支援 public void bRequestSupport() { System.out.println("這里是B的請求支援"); } private boolean isSupport() { Random rand = new Random(); return rand.nextBoolean(); } }
代碼比較長,但也比較簡單。定義了處理各個對象關系的業(yè)務方法,把依賴關系轉移到了這個業(yè)務方法中,而同事類只需要委托中介者協(xié)調各個同事類的業(yè)務邏輯。
public abstract class Colleague { protected Mediator mediator; public Colleague(Mediator mediator) { this.mediator = mediator; } }
很簡單的就一個構造方法,繼續(xù)看具體同事類的實現(xiàn),我先把各個同事類的代碼都貼出來:
// A戰(zhàn)區(qū) public class SituationA extends Colleague { public SituationA(Mediator mediator) { super(mediator); } // 請求支援 public void aRequestSupport() { super.mediator.execute("aRequestSupport"); } } // B戰(zhàn)區(qū) public class SituationB extends Colleague { public SituationB(Mediator mediator) { super(mediator); } // 請求支援 public void bRequestSupport() { super.mediator.execute("bRequestSupport"); } public void bSupport(boolean isSupport) { if (isSupport) { System.out.println("SituationB:Copy that,還有五秒鐘到達戰(zhàn)場"); } else { System.out.println("-------B也正在被攻打--------"); System.out.println("SituationB:支援你妹,我也正在被攻打"); } } } // C戰(zhàn)區(qū) public class SituationC extends Colleague { public SituationC(Mediator mediator) { super(mediator); } // 請求支援 public void cRequestSupport() { super.mediator.execute("cRequestSupport"); } public void cSupport(boolean isSupport) { if (isSupport) { System.out.println(getClass().getSimpleName() + ":Copy that,還有五秒鐘到達戰(zhàn)場"); } else { System.out.println(getClass().getSimpleName() + ":不好意思,來遲一步了,正在前往別的戰(zhàn)區(qū)支援"); } } }
跟前面說的一樣,通過cRequestSupport方法中的execute委托中介者處理同事類的業(yè)務邏輯,本身只負責處理自身的業(yè)務。
最后來看客戶端的實現(xiàn),代碼如下:
public class Client { public static void main(String[] args) { Mediator mediator = new Command(); System.out.println("-------A被攻打,請求支援--------"); SituationA situationA = new SituationA(mediator); situationA.aRequestSupport(); } }
可以看到,表面上請求還是從A發(fā)出,但是A已經委托了中介者進行業(yè)務邏輯和流程的處理。這樣的好處就是每個同事類的職責都很清晰,跟其他同事類有關聯(lián)的都委托到中介者,本身專注自己的行為。
運行客戶端,結果如下:
-------A被攻打,請求支援--------三、中介者模式的優(yōu)缺點 優(yōu)點
SituationA:這里是A戰(zhàn)區(qū),現(xiàn)在被敵方攻打,請求支援
-------B也正在被攻打--------
SituationB:支援你妹,我也正在被攻打
-------A又向C請求支援--------
SituationC:Copy that,還有五秒鐘到達戰(zhàn)場
1)解耦。把同事類原來一對多的依賴變成一對一的依賴,降低同事類的耦合度,同時也符合了迪米特原則。
缺點1)中介者模式把業(yè)務流程和協(xié)調都寫在中介者,當同事類越多,中介者的業(yè)務就越復雜,造成不好管理的弊端。
2)中介者模式還有一個明顯的缺點,如果要增減同事類,必須得修改抽象中介者角色和具體中介者角色類。
四、模式擴展 中介者模式和觀察者模式混編為什么要跟觀察者模式組合混編?首先,上面提到了如果要增加或者刪除同事類,必須對中介者這個角色進行修改,因為中介者角色的業(yè)務邏輯相對比較集中和復雜,修改中介者角色會比較麻煩。另外一點是,使用觀察者模式實現(xiàn)同事類(被觀察者)的通信可以優(yōu)化中介者的業(yè)務邏輯流程,避免過多使用if...else。
同事類通知->中介者協(xié)調處理->中介者通知同事類
其實可以說成中介者模式是通過觀察者模式實現(xiàn)的,都是事件驅動模型。這里簡單闡述下原理,把中介者作為觀察者,即中介者角色實現(xiàn)Observer接口,重寫update方法(重點就在update,同事類跟中介者,中介者月同事類之間的通信就在這實現(xiàn))。同事類繼承Observable被觀察者類,通過notifyObservers可以與中介者通信。這樣就在相當于觀察者模式的基礎上(觀察者模式的交互路徑較短),在中介者中增加了消息轉發(fā)的功能,也就是說同事類之間的通信經過了中介者。
中介者模式VS門面模式先簡單介紹下門面模式。要求一個子系統(tǒng)的外部與其內部的通信必須通過一個統(tǒng)一的對象進行,這就是門面模式。門面模式主要的是提供了一個高層次的接口,也就是所謂的一個統(tǒng)一對象,通過它跟子系統(tǒng)進行通信。這樣做的好處就是,第一,外部與系統(tǒng)內部解耦,減少相互之間的依賴;第二,增加系統(tǒng)內部的靈活性,系統(tǒng)內部變化不影響外部跟門面角色的關系。比如拍照,可以用手機拍,也可以用單反相機拍,把手機和單反封裝在一起,外部只能看到一個攝像頭,你只能說拍照,里面到底是手機拍還是單反拍是不知道的。
中介者模式和門面模式同樣的都是通過封裝一個角色來進行隔離解耦,但中介者強調的是中介協(xié)調同事類之間的通信,門面模式則是通過門面對內部進行隔離。另外,中介者模式的通信是雙向的,而門面模式的通信是單向的。
總結系統(tǒng)中多個對象之間相互依賴,并且依賴關系結構復雜導致對象之間的耦合度增大,修改難度大,這個時候可以考慮使用中介者模式來梳理對象之間的通信,達到降低對象之間耦合度的效果。中介者模式就到這,下一篇命令模式,您的點贊和關注是我的動力,欽敬欽敬!
設計模式Java源碼GitHub下載:https://github.com/jetLee92/DesignPattern
更多干貨關注微信公眾號“Jet啟思”
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/68679.html
摘要:模板方法模式定義定義抽象類并且聲明一些抽象基本方法供子類實現(xiàn)不同邏輯,同時在抽象類中定義具體方法把抽象基本方法封裝起來,這就是模板方法模式。 近日,ofo小黃車宣布入駐法國巴黎,正式進入全球第20個國家,共享單車已然改變了我們的出行方式。就拿我自己來說,每當下班出地鐵的第一件事,以光速鎖定一輛共享單車,百米沖刺的速度搶在別人之前占領它。 而大家都是重復著同樣的動作,拿出手機開鎖、騎車、...
摘要:在地球上最大的中介者就是聯(lián)合國了,它主要用來維護國際和平與安全解決國際間經濟社會文化和人道主義性質的問題。所以對于關系比較復雜的系統(tǒng),我們?yōu)榱藴p少對象之間的關聯(lián)關系,使之成為一個松耦合系統(tǒng),我們就需要使用中介者模式。 中介者模式(Mediator Pattern)屬于行為型模式的一種,用一個中介對象來封裝一系列的對象交互。中介者使各對象不需要顯式地相互引用,從而使其耦合松散,而且可以獨...
閱讀 3214·2023-04-25 18:43
閱讀 892·2021-11-24 09:39
閱讀 1361·2021-10-14 09:43
閱讀 3890·2021-09-22 15:58
閱讀 1899·2019-08-29 17:18
閱讀 410·2019-08-29 14:14
閱讀 3078·2019-08-29 13:01
閱讀 1616·2019-08-29 12:33