1.初識中介者模式
用一個中介對象來封裝一系列的對象交互哮洽。中介者使得各對象不需要顯式地相互引用,從而使其耦合松散义钉,而且可以獨立的改變它們之間的交互鄙麦。
- Mediator:中介者接口。在里面定義各個同事之間交互需要的方法馋吗,可以是公共的通訊方法焕盟,比如changed方法,大家都用宏粤,也可以是小范圍的交互方法脚翘。
ConcreteMediator:具體中介者實現(xiàn)對象。它需要了解并維護各個同事對象绍哎,并負責具體的協(xié)調各同事對象的交互關系来农。
Colleague:同事類的定義,通常實現(xiàn)成為抽象類崇堰,主要負責約束同事對象的類型沃于,并實現(xiàn)一些具體同事類之間的公共功能,比如:每個具體同事類都應該知道中介者對象海诲,也就是具體同事類都會持有中介者對象繁莹,就可以定義到這個類里面。
ConcreteColleague:具體的同事類特幔,實現(xiàn)自己的業(yè)務咨演,在需要與其它同事通訊的時候,就與持有的中介者通信敬辣,中介者會負責與其它的同事交互雪标。
2.體會中介者模式
2.1 場景問題——使用電腦來看電影
為了演示,考慮一個稍微具體點的功能溉跃。在日常生活中村刨,我們經(jīng)常使用電腦來看電影,把這個過程描述出來撰茎,這里僅僅考慮正常的情況嵌牺,也就是有主板的情況,簡化后假定會有如下的交互過程:
- step1.首先是光驅要讀取光盤上的數(shù)據(jù),然后告訴主板逆粹,它的狀態(tài)改變了
- step2.主板去得到光驅的數(shù)據(jù)募疮,把這些數(shù)據(jù)交給CPU進行分析處理
- step3.CPU處理完后,把數(shù)據(jù)分成了視頻數(shù)據(jù)和音頻數(shù)據(jù)僻弹,通知主板阿浓,它處理完了
- step4.主板去得到CPU處理過后的數(shù)據(jù),分別把數(shù)據(jù)交給顯卡和聲卡蹋绽,去顯示出視頻和發(fā)出聲音
當然這是一個持續(xù)的芭毙、不斷重復的過程,從而形成不間斷的視頻和聲音卸耘,具體的運行過程不在討論之列退敦,假設就有如上簡單的交互關系就可以了。也就是說想看電影蚣抗,把光盤放入光驅侈百,光驅開始讀盤,就可以看電影了
2.2 使用模式的解決方案
3.理解中介者模式
3.1 認識中介者模式
3.1.1 中介者模式的功能
中介者的功能非常簡單翰铡,就是封裝對象之間的交互钝域。如果一個對象的操作會引起其它相關對象的變化,或者是某個操作需要引起其它對象的后續(xù)或連帶操作锭魔,而這個對象又不希望自己來處理這些關系网梢,那么就可以找中介者,把所有的麻煩扔給它赂毯,只在需要的時候通知中介者,其它的就讓中介者去處理就可以了拣宰。
反過來党涕,其它的對象在操作的時候,可能會引起這個對象的變化巡社,也可以這么做膛堤。最后對象之間就完全分離了,誰都不直接跟其它對象交互晌该,那么相互的關系肥荔,全部被集中到中介者對象里面了,所有的對象就只是跟中介者對象進行通信朝群,相互之間不再有聯(lián)系燕耿。
把所有對象之間的交互都封裝在中介者當中,無形中還得到另外一個好處姜胖,就是能夠集中的控制這些對象的交互關系誉帅,這樣有什么變化的時候,修改起來就很方便。
3.1.2 需要Mediator接口嗎
有沒有使用Mediator接口的必要蚜锨,取決于是否會提供多個不同的中介者實現(xiàn)档插。如果中介者實現(xiàn)只有一個的話,而且預計中也沒有需要擴展的要求亚再,那么就可以不定義Mediator接口郭膛,讓各個同事對象直接使用中介者實現(xiàn)對象;如果中介者實現(xiàn)不只一個氛悬,或者預計中有擴展的要求则剃,那么就需要定義Mediator接口,讓各個同事對象來面向中介者接口編程圆雁,而無需關心具體的中介者實現(xiàn)忍级。
3.1.3 同事關系
在中介者模式中,要求這些類都要繼承相同的類伪朽,也就是說轴咱,這些對象從某個角度講是同一個類型,算是兄弟對象烈涮。
正是這些兄弟對象之間的交互關系很復雜朴肺,才產(chǎn)生了把這些交互關系分離出去,單獨做成中介者對象坚洽,這樣一來戈稿,這些兄弟對象就成了中介者對象眼里的同事。
3.1.4 同事和中介者的關系
中介者對象和同事對象之間是相互依賴的讶舰。
3.1.5 如何實現(xiàn)同事和中介者的通信
一種實現(xiàn)方式是在Mediator接口中定義一個特殊的通知接口鞍盗,作為一個通用的方法,讓各個同事類來調用這個方法跳昼。
另外一種實現(xiàn)方式是可以采用觀察者模式般甲,把Mediator實現(xiàn)成為觀察者,而各個同事類實現(xiàn)成為Subject鹅颊,這樣同事類發(fā)生了改變敷存,會通知Mediator。 Mediator在接到通知過后堪伍,會與相應的同事對象進行交互锚烦。
3.1.6 中介者模式的調用順序示意圖
3.2 廣義中介者
3.2.1 標準的中介者模式在實際使用中的困難
1.是否有必要為同事對象定義一個公共的父類?
大家都知道帝雇,Java是單繼承的涮俄,為了使用中介者模式,就讓這些同事對象繼承一個父類摊求,這是很不好的禽拔;再說了刘离,這個父類目前也沒有什么特別的公共功能,也就是說繼承它也得不到多少好處睹栖。
在實際開發(fā)中硫惕,很多相互交互的對象本身是沒有公共父類的,強行加上一個父類野来,會讓這些對象實現(xiàn)起來特別別扭恼除。
2.同事類有必要持有中介者對象嗎?
同事類需要知道中介者對象曼氛,以便當它們發(fā)生改變的時候豁辉,能夠通知中介者對象,但是否需要作為屬性舀患,并通過構造方法傳入徽级,這么強的依賴關系呢?
也可以有簡單的方式去通知中介對象聊浅,比如把中介對象做成單例餐抢,直接在同事類的方法里面去調用中介者對象。
3.是否需要中介者接口低匙?
在實際開發(fā)中旷痕,很常見的情況是不需要中介者接口的,而且中介者對象也不需要創(chuàng)建很多個實例顽冶,因為中介者是用來封裝和處理同事對象的關系的欺抗,它一般是沒有狀態(tài)需要維護的,因此中介者通城恐兀可以實現(xiàn)成單例绞呈。
4.中介者對象是否需要持有所有的同事?
雖說中介者對象需要知道所有的同事類间景,這樣中介者才能與它們交互报强。但是是否需要做為屬性這么強烈的依賴關系,而且中介者對象在不同的關系維護上拱燃,可能會需要不同的同事對象的實例,因此可以在中介者處理的方法里面去創(chuàng)建力惯、或者獲取碗誉、或者從參數(shù)傳入需要的同事對象。
5.中介者對象只是提供一個公共的方法父晶,來接受同事對象的通知嗎哮缺?
從示例就可以看出來,在公共方法里甲喝,還是要去區(qū)分到底是誰調過來尝苇,這還是簡單的,還沒有去區(qū)分到底是什么樣的業(yè)務觸發(fā)調用過來的,因為不同的業(yè)務糠溜,引起的與其它對象的交互是不一樣的淳玩。
因此在實際開發(fā)中,通常會提供具體的業(yè)務通知方法非竿,這樣就不用再去判斷到底是什么對象蜕着,具體是什么業(yè)務了。
3.2.2 對標準的中介者模式在實際使用中的改進
基于上面的考慮红柱,在實際應用開發(fā)中承匣,經(jīng)常會簡化中介者模式,來使開發(fā)變得簡單锤悄,比如有如下的簡化
- 1)通常會去掉同事對象的父類韧骗,這樣可以讓任意的對象,只要需要相互交互零聚,就可以成為同事袍暴;
- 2)還有通常不定義Mediator接口,把具體的中介者對象實現(xiàn)成為單例握牧;
- 3)另外一點就是同事對象不再持有中介者容诬,而是在需要的時候直接獲取中介者對象并調用;中介者也不再持有同事對象沿腰,而是在具體處理方法里面去創(chuàng)建览徒、或者獲取、或者從參數(shù)傳入需要的同事對象颂龙。
把這樣經(jīng)過簡化习蓬、變形使用的情況稱為廣義中介者。
3.2.3 廣義中介者示例——部門與人員
3.2.3.1 部門和人員的關系
是多對多的
3.2.3.2 問題的出現(xiàn)
想想部門和人員的功能交互措嵌,舉幾個常見的功能:
- 1)部門被撤銷
- 2)部門之間進行合并
- 3)人員離職
- 4)人員從一個部門調職到另外一個部門
想想要實現(xiàn)這些功能躲叼,按照前面的設計,該怎么做呢企巢?
- 1)系統(tǒng)運行期間枫慷,部門被撤銷了,就意味著這個部門不存在了浪规,可是原來這個部門下所有的人員或听,每個人員的所屬部門中都有這個部門呢,那么就需要先通知所有的人員笋婿,把這個部門從它們的所屬部門中去掉誉裆,然后才可以清除這個部門。
- 2)部門合并缸濒,是合并成一個新的部門呢足丢,還是把一個部門并入到另一個部門粱腻?如果是合并成一個新的部門,那么需要把原有的兩個部門撤銷斩跌,然后再新增一個部門绍些;如果是把一個部門合并到另一個部門里面,那就是撤銷掉一個部門滔驶,然后把這個部門下的人員移動到這個部門遇革。不管是那種情況,都面臨著需要通知相應的人員進行更改這樣的問題揭糕。
- 3)人員離職了萝快,反過來就需要通知他所屬于的部門,從部門的擁有人員的記錄中去除掉這個人員著角。
- 4)人員調職揪漩,同樣需要通知相關的部門,先從原來的部門中去除掉吏口,然后再到新的部門中添加上奄容。
看了上述的描述,感覺如何产徊?
麻煩的根源在什么地方呢昂勒?仔細想想,對了舟铜,麻煩的根源就在于部門和人員之間的耦合戈盈,這樣導致操作人員的時候,需要操作所有相關的部門谆刨,而操作部門的時候又需要操作所有相關的人員塘娶,使得部門和人員攪和在了一起。
3.2.3.3 中介者來解決
找到了根源就好辦了痊夭,采用中介者模式刁岸,引入一個中介者對象來管理部門和人員之間的關系,就能解決這些問題了她我。
如果采用標準的中介者模式虹曙,想想上面提出的那些問題點吧,就知道實現(xiàn)起來會很別扭番舆。因此采用廣義的中介者來解決根吁,這樣部門和人員就完全解耦了,也就是說部門不知道人員合蔽,人員也不知道部門,它們完全分開介返,它們之間的關系就完全由中介者對象來管理了拴事。
3.3 中介者模式的優(yōu)缺點
- 松散耦合
- 集中控制交互
- 多對多變成一對多
- 過度集中化
4.思考中介者模式
4.1 中介者模式的本質
封裝交互
4.2 何時選用
- 1)如果一組對象之間的通信方式比較復雜沃斤,導致相互依賴、結構混亂刃宵,可以采用中介者模式衡瓶,把這些對象相互的交互管理起來,各個對象都只需要和中介者交互牲证,從而使得各個對象松散耦合哮针,結構也更清晰易懂
- 2)如果一個對象引用很多的對象,并直接跟這些對象交互坦袍,導致難以復用該對象十厢。可以采用中介者模式捂齐,把這個對象跟其它對象的交互封裝到中介者對象里面蛮放,這個對象就只需要和中介者對象交互就可以了