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