設(shè)計(jì)模式學(xué)習(xí)之中介者模式

我們平時(shí)寫代碼的過程罚屋,一個(gè)類必然會(huì)與其他類產(chǎn)生依賴關(guān)系,如果這種依賴關(guān)系如網(wǎng)狀般錯(cuò)綜復(fù)雜嗅绸,那么必然會(huì)影響我們的代碼邏輯以及執(zhí)行效率脾猛,適當(dāng)?shù)厥褂弥薪檎吣J娇梢詫?duì)這種依賴關(guān)系進(jìn)行解耦使邏輯結(jié)構(gòu)清晰,本篇博客鱼鸠,我們就一起學(xué)習(xí)中介者模式猛拴。

定義及使用場(chǎng)景

定義:中介者模式包裝了一系列對(duì)象相互作用的方式,使得這些對(duì)象不必相互明顯作用蚀狰。從而使它們可以松散耦合愉昆。當(dāng)某些對(duì)象之間的作用發(fā)生改變時(shí),不會(huì)立即影響其他的一些對(duì)象之間的作用麻蹋。保證這些作用可以彼此獨(dú)立的變化跛溉。

使用場(chǎng)景:

當(dāng)對(duì)象之間的交互操作很多且每個(gè)對(duì)象的行為操作都依賴彼此時(shí),為防止在修改一個(gè)對(duì)象的行為時(shí)扮授,同時(shí)涉及很多其他對(duì)象的行為芳室,可使用中介者模式。

UML類圖

Mediator:抽象中介者角色刹勃,定義了同事對(duì)象到中介者對(duì)象的接口堪侯,一般以抽象類的方式實(shí)現(xiàn)。ConcreteMediator:具體中介者角色荔仁,繼承于抽象中介者伍宦,實(shí)現(xiàn)了父類定義的方法芽死,它從具體的同事對(duì)象接受消息,向具體同事對(duì)象發(fā)出命令次洼。

Colleague:抽象同事類角色关贵,定義了中介者對(duì)象的接口,它只知道中介者而不知道其他的同事對(duì)象卖毁。

ConcreteColleague1坪哄、ConcreteColleague2:具體同事類角色,繼承于抽象同事類势篡,每個(gè)具體同事類都知道本身在小范圍的行為,而不知道在大范圍內(nèi)的目的模暗。

中介者模式通用代碼

抽象同事類:

Colleague.java

package?com.qianfeng.agent;

public?abstract?class?Colleague {

? ??????????protected?Mediator mediator;

public?void?setMediator(Mediator mediator) {

? ??????????this.mediator=mediator;

}

? ??????????public?abstract?void?operation();

}

具體同事類

ConcreteColleagueA.java && ConcreteColleagueB.java

package?com.qianfeng.agent;

public?class?ConcreteColleagueA extends?Colleague{

? ??????????????????public?void?notifyColleagueB() {

????????????????????????????mediator.notifyColleagueB();

}

@Override

public?void?operation() {

????????????System.out.println("this is ConcreteColleagueA's operation\n");

????????}

}

package?com.qianfeng.agent;

public?class?ConcreteColleagueB extends?Colleague{

? ??????????public?void?notifyColleagueA() {

????????????????????????mediator.notifyColleagueA();

}

@Override

public?void?operation() {

????????????System.out.print("this is ConcreteColleagueB's operation\n");

????????}

}

抽象中介者角色:

Mediator.java

package?com.qianfeng.agent;

public?abstract?class?Mediator {

? ??????protected?Colleague colleagueA;

? ???????protected?Colleague colleagueB;

/**

?* @param?colleagueA

?* @param?colleagueB

?*/

public?Mediator(Colleague colleagueA, Colleague colleagueB) {

? ?????????????????????this.colleagueA?= colleagueA;

? ??????????????????????this.colleagueB?= colleagueB;

}

public?abstract?void?notifyColleagueA();

????????public?abstract?void?notifyColleagueB();

}

測(cè)試代碼:

ConcretrMediator.java

package?com.qianfeng.agent;

public?class?ConcreteMediator extends?Mediator{

public?ConcreteMediator(Colleague colleagueA, Colleague colleagueB) {

? ??????????????super(colleagueA, colleagueB);

}

@Override

public?void?notifyColleagueA() {

? ? ? ??if(colleagueA?!=null) {

????????????????colleagueA.operation();

????????????}

}

@Override

public?void?notifyColleagueB() {

? ? ? ? ? ??if(colleagueB?!=null) {

????????????????????colleagueB.operation();

????????????????}

????????}

}

兩個(gè)Colleague 類成功通過 Mediator 進(jìn)行了相互作用禁悠。上面是中介者模式的標(biāo)準(zhǔn)寫法,在平時(shí)項(xiàng)目中兑宇,硬是將各業(yè)務(wù)的類抽象出一個(gè) Colleague 父類是不太合理的碍侦,因?yàn)樽宇愔g的業(yè)務(wù)邏輯的不同,導(dǎo)致他們很難抽象出一些公用方法隶糕,所以這時(shí)候使用中介者模式瓷产,可以省去 Colleague 這個(gè)角色,讓 Mediator 直接依賴于幾個(gè)同事子類枚驻;同時(shí)也可以不定義Mediator接口濒旦,把具體的中介者對(duì)象實(shí)現(xiàn)成為單例,這樣同事對(duì)象不再持有中介者再登,而是在需要的時(shí)候直接獲取中介者對(duì)象并調(diào)用尔邓;中介者也不再持有同事對(duì)象,而是在具體處理方法里面去創(chuàng)建锉矢,或獲取梯嗽,或從數(shù)據(jù)傳入需要的同事對(duì)象。

中介者模式例子

同事:

//抽象同事類 ?

abstract?class?AbstractColleague { ?

????protected?AbstractMediator?mediator; ?

????/**既然有中介者沽损,那么每個(gè)具體同事必然要與中介者有聯(lián)系灯节, ?

?????* 否則就沒必要存在于 這個(gè)系統(tǒng)當(dāng)中,這里的構(gòu)造函數(shù)相當(dāng) ?

?????* 于向該系統(tǒng)中注冊(cè)一個(gè)中介者绵估,以取得聯(lián)系 ?

?????*/?

????public?AbstractColleague(AbstractMediator?mediator) { ?

????????????????????????this.mediator?= mediator; ?

????} ?

????// 在抽象同事類中添加用于與中介者取得聯(lián)系(即注冊(cè))的方法 ?

????public?void?setMediator(AbstractMediator?mediator) { ?

????????????????????????this.mediator?= mediator; ?

????} ?

} ?

//具體同事A ?

class?ColleagueA extends?AbstractColleague { ?


????//每個(gè)具體同事都通過父類構(gòu)造函數(shù)與中介者取得聯(lián)系 ?

????public?ColleagueA(AbstractMediator?mediator) { ?

????????????????????????super(mediator); ?

????} ?


????//每個(gè)具體同事必然有自己分內(nèi)的事炎疆,沒必要與外界相關(guān)聯(lián) ?

????public?void?self() { ?

????????????????????System.out.println("同事A --> 做好自己分內(nèi)的事情 ..."); ?

????} ?


????//每個(gè)具體同事總有需要與外界交互的操作,通過中介者來處理這些邏輯并安排工作 ?

????public?void?out() { ?

????????????????System.out.println("同事A --> 請(qǐng)求同事B做好分內(nèi)工作 ..."); ?

????????????????super.mediator.execute("ColleagueB", "self"); ?

????} ?

} ?

中介者:

//抽象中介者 ?

abstract?class?AbstractMediator { ?

????????????????//中介者肯定需要保持有若干同事的聯(lián)系方式 ?

????????????????protected?Hashtable colleagues?= new?Hashtable(); ?

????????????????//中介者可以動(dòng)態(tài)地與某個(gè)同事建立聯(lián)系 ?

????public?void?addColleague(String name, AbstractColleague?c) { ?

????????????????this.colleagues.put(name, c); ?

????} ? ??

????//中介者也可以動(dòng)態(tài)地撤銷與某個(gè)同事的聯(lián)系 ?

????public?void?deleteColleague(String name) { ?

????????????????this.colleagues.remove(name); ?

????} ?

????//中介者必須具備在同事之間處理邏輯壹士、分配任務(wù)磷雇、促進(jìn)交流的操作 ?

????????????public?abstract?void?execute(String name, String method); ??

} ?

//具體中介者 ?

class?Mediator extends?AbstractMediator{ ?

????//中介者最重要的功能,來回奔波與各個(gè)同事之間 ?

????public?void?execute(String name, String method) { ?

????????????????if("self".equals(method)){ ?//各自做好分內(nèi)事 ?

????????????????????????if("ColleagueA".equals(name)) { ?

????????????????????????????????ColleagueA?colleague?= (ColleagueA)super.colleagues.get("ColleagueA"); ?

????????????????????????????????colleague.self(); ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }else?{ ?

????????????????????????????ColleagueB?colleague?= (ColleagueB)super.colleagues.get("ColleagueB"); ?

???????????????????????????colleague.self(); ?

????????????} ?

????????????????????????????????}else?{ //與其他同事合作 ?

????????????????????????????????if("ColleagueA".equals(name)) { ?

????????????????????????????ColleagueA?colleague?= (ColleagueA)super.colleagues.get("ColleagueA"); ?

????????????????????????????colleague.out(); ?

???????????????????????????????}else?{ ?

????????????????ColleagueB?colleague?= (ColleagueB)super.colleagues.get("ColleagueB"); ?

????????????????colleague.out(); ?

????????????} ?

????????} ?

????} ?

}

測(cè)試類:

//測(cè)試類 ?

public?class?Client?{ ?

????public?static?void?main(String[] args) { ?

????????//創(chuàng)建一個(gè)中介者 ?

????????AbstractMediator?mediator?= new?Mediator(); ?

????????//創(chuàng)建兩個(gè)同事 ?

????????ColleagueA?colleagueA?= new?ColleagueA(mediator); ?

????????ColleagueB?colleagueB?= new?ColleagueB(mediator); ?

????????//中介者分別與每個(gè)同事建立聯(lián)系 ?

????????mediator.addColleague("ColleagueA", colleagueA); ?

????????mediator.addColleague("ColleagueB", colleagueB); ?

????????//同事們開始工作 ?

????????colleagueA.self(); ?

????????colleagueA.out(); ?

????????System.out.println("======================合作愉快躏救,任務(wù)完成唯笙!\n"); ?

????????colleagueB.self(); ?

????????colleagueB.out(); ?

????????System.out.println("======================合作愉快螟蒸,任務(wù)完成!"); ?

????} ?

}

具體中介者類Mediator中的execute()方法中現(xiàn)在就有一堆冗長(zhǎng)的判斷代碼了崩掘。雖然可以把它分解并增加到Mediator類中的其它private方法中七嫌,但是具體的業(yè)務(wù)邏輯是少不了的。

所以苞慢,在解耦同事類之間的聯(lián)系的同時(shí)诵原,中介者自身也不免任務(wù)過重,因?yàn)閹缀跛械臉I(yè)務(wù)邏輯都交代到中介者身上了挽放,這就是中介者模式的不足之處绍赛。

對(duì)上面的例子還可以進(jìn)行如下優(yōu)化:

修改后的同事

//抽象同事類 ?

abstract?class?AbstractColleague { ?

????????protected?AbstractMediator?mediator; ? ? ?

????????//舍去在構(gòu)造函數(shù)中建立起與中介者的聯(lián)系 ?

????????// ?public AbstractColleague(AbstractMediator mediator) { ?

????????// ?????this.mediator = mediator; ?

????????// ?} ?

????????// 在抽象同事類中添加用于與中介者取得聯(lián)系(即注冊(cè))的方法 ?

????????public?void?setMediator(AbstractMediator?mediator) { ?

????????????????this.mediator?= mediator; ?

????????} ?

} ?

//具體同事A ?

class?ColleagueA extends?AbstractColleague { ?

????????????????//舍去在構(gòu)造函數(shù)中建立起與中介者的聯(lián)系 ?

? ? ? ? ? ? ?// public ColleagueA(AbstractMediator mediator) { ?

? ? ? ? ? ? ? ?// ? ? ? ? ? super(mediator); ?

? ? ? ? ? ? ? //} ?

????//每個(gè)具體同事必然有自己分內(nèi)的事,沒必要與外界相關(guān)聯(lián) ?

????public?void?self() { ?

????????????System.out.println("同事A --> 做好自己分內(nèi)的事情 ..."); ?

????} ?

????//每個(gè)具體同事總有需要與外界交互的操作辑畦,通過中介者來處理這些邏輯并安排工作 ?

????public?void?out() { ?

????????System.out.println("同事A --> 請(qǐng)求同事B做好分內(nèi)工作 ..."); ?

????????super.mediator.execute("ColleagueB", "self"); ?

????} ?

} ?

//具體同事B ?

class?ColleagueB extends?AbstractColleague { ?

????????????????????//舍去在構(gòu)造函數(shù)中建立起與中介者的聯(lián)系 ?

? ? ? ? ? ? ? // ?public ColleagueB(AbstractMediator mediator) { ?

? ? ? ? ? ? ? ?// ?????super(mediator); ?

????????????????// ?} ?


????????public?void?self() { ?

????????????????System.out.println("同事B --> 做好自己分內(nèi)的事情 ..."); ?

????} ?

????????public?void?out() { ?

????????????????System.out.println("同事B --> 請(qǐng)求同事A做好分內(nèi)工作 ?..."); ?

????????????????super.mediator.execute("ColleagueA", "self"); ?

????} ?

}

修改后的中介者:

//抽象中介者 ?

abstract?class?AbstractMediator { ?

????????????//中介者肯定需要保持有若干同事的聯(lián)系方式 ?

????????protected?Hashtable colleagues?= new?Hashtable(); ?

????????????//中介者可以動(dòng)態(tài)地與某個(gè)同事建立聯(lián)系 ?

????????public?void?addColleague(String name, AbstractColleague?c) { ?

????????????????// 在中介者這里幫助具體同事建立起于中介者的聯(lián)系 ?

????????????????c.setMediator(this); ?

????????????????this.colleagues.put(name, c); ?

????????} ? ??

????????????//中介者也可以動(dòng)態(tài)地撤銷與某個(gè)同事的聯(lián)系 ?

????????????public?void?deleteColleague(String name) { ?

????????????????????????????this.colleagues.remove(name); ?

????????????} ?

? ? ? ? ? ?//中介者必須具備在同事之間處理邏輯吗蚌、分配任務(wù)、促進(jìn)交流的操作 ?

????????????public?abstract?void?execute(String name, String method); ??

????????????}

測(cè)試類:

public?class?Client?{ ?

????public?static?void?main(String[] args) { ?

????????????//創(chuàng)建一個(gè)中介者 ?

???????????AbstractMediator?mediator?= new?Mediator(); ?

????????????//不用構(gòu)造函數(shù)為具體同事注冊(cè)中介者來取得聯(lián)系了 ?

????????????//ColleagueA colleagueA = new ColleagueA(mediator); ?

????????????//ColleagueB colleagueB = new ColleagueB(mediator); ?

????????????ColleagueA?colleagueA?= new?ColleagueA(); ?

????????????ColleagueB?colleagueB?= new?ColleagueB(); ?

????????????//中介者分別與每個(gè)同事建立聯(lián)系 ?

????????????mediator.addColleague("ColleagueA", colleagueA); ?

????????????mediator.addColleague("ColleagueB", colleagueB); ?

????????????//同事們開始工作 ?

???????????colleagueA.self(); ?

? ? ? ? ? ?colleagueA.out(); ?

????????????System.out.println("======================合作愉快纯出,任務(wù)完成蚯妇!\n"); ?

????????????colleagueB.self(); ?

????????????colleagueB.out(); ?

????????????System.out.println("======================合作愉快,任務(wù)完成暂筝!"); ?

????} ?

}

總結(jié)

1.優(yōu)點(diǎn)

(1)適當(dāng)?shù)厥褂弥薪檎吣J娇梢员苊馔骂愔g的過度耦合箩言,使得各同事類之間可以相對(duì)獨(dú)立地使用。

(2)使用中介者模式可以將對(duì)象的行為和協(xié)作進(jìn)行抽象焕襟,能夠比較靈活的處理對(duì)象間的相互作用陨收。

(3)使用中介者模式可以將對(duì)象間多對(duì)多的關(guān)聯(lián)轉(zhuǎn)變?yōu)橐粚?duì)多的關(guān)聯(lián),使對(duì)象間的關(guān)系易于理解和維護(hù)鸵赖。

2.缺點(diǎn)

????中介者模式是一種比較常用的模式畏吓,也是一種比較容易被濫用的模式蓉冈。對(duì)于大多數(shù)的情況森书,同事類之間的關(guān)系不會(huì)復(fù)雜到混亂不堪的網(wǎng)狀結(jié)構(gòu)渔工,因此畜份,大多數(shù)情況下领追,將對(duì)象間的依賴關(guān)系封裝的同事類內(nèi)部就可以的睬涧,沒有必要非引入中介者模式馅而。濫用中介者模式瓜晤,只會(huì)讓事情變的更復(fù)雜包吝。所以饼煞,我們決定使用中介者模式之前要多方考慮、權(quán)衡利弊诗越。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末砖瞧,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子嚷狞,更是在濱河造成了極大的恐慌块促,老刑警劉巖荣堰,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異竭翠,居然都是意外死亡振坚,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門斋扰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來渡八,“玉大人,你說我怎么就攤上這事传货∈瑚ⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵问裕,是天一觀的道長(zhǎng)哥艇。 經(jīng)常有香客問我,道長(zhǎng)僻澎,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任十饥,我火速辦了婚禮窟勃,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘逗堵。我一直安慰自己秉氧,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布蜒秤。 她就那樣靜靜地躺著汁咏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪作媚。 梳的紋絲不亂的頭發(fā)上攘滩,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音纸泡,去河邊找鬼漂问。 笑死,一個(gè)胖子當(dāng)著我的面吹牛女揭,可吹牛的內(nèi)容都是我干的蚤假。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼吧兔,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼磷仰!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起境蔼,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤灶平,失蹤者是張志新(化名)和其女友劉穎伺通,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體民逼,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡泵殴,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了拼苍。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片笑诅。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖疮鲫,靈堂內(nèi)的尸體忽然破棺而出吆你,到底是詐尸還是另有隱情,我是刑警寧澤俊犯,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布妇多,位于F島的核電站,受9級(jí)特大地震影響燕侠,放射性物質(zhì)發(fā)生泄漏者祖。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一绢彤、第九天 我趴在偏房一處隱蔽的房頂上張望七问。 院中可真熱鬧,春花似錦茫舶、人聲如沸械巡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)讥耗。三九已至,卻和暖如春疹启,著一層夾襖步出監(jiān)牢的瞬間古程,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來泰國(guó)打工喊崖, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留籍琳,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓贷祈,卻偏偏與公主長(zhǎng)得像趋急,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子势誊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容