8.中介者模式 -Mediator

定義

​   用一箇中介對象來封裝一系列的對象交互。中介者使得各對象不須要顯式地相互引用,從而使其耦合鬆散,並且能夠獨立的改變它們之間的交互。java

結構和說明

 

Mediator:git

  中介者接口。在裏面定義各個同事之間交互須要的方法,能夠是公共的通信方法,好比changed方法,你們都用,也能夠是小範圍的交互方法。編程

ConcreteMediator:spa

  ​ 具體中介者實現對象。它須要瞭解並維護各個同事對象,並負責具體的協調各同事對象的交互關係。設計

Colleague:3d

​   同事類的定義,一般實現成爲抽象類,主要負責約束同事對象的類型,並實現一些具體同事類之間的公共功能,好比:每一個具體同事類都應該知道中介者對象,也就是具體同事類都會持有中介者對象,就能夠定義到這個類裏面。視頻

ConcreteColleague:對象

  具體的同事類,實現本身的業務,在須要與其它同事通信的時候,就與持有的中介者通訊,中介者會負責與其它的同事交互。blog

體會中介者模式

若是沒有主板​ 若是電腦裏面沒有了主板,那麼各個配件之間就必須自行相互交互,以互相傳送數據,理論上說,基本上各個配件相互之間都存在交互數據的可能繼承

 

有了主板,各個配件的交互徹底經過主板來完成,每一個配件都只須要和主板交互,而主板知道如何和全部的配件打交道,那就簡單多了

存在的問題?

  若是上面的狀況發生在軟件開發上呢?

   若是把每一個電腦配件都抽象成爲一個類或者是子系統,那就至關於出現了多個類之間相互交互,並且交互還很繁瑣,致使每一個類都必須知道全部須要交互的類,也就是咱們常說的類和類耦合了,是否是很麻煩?

​   這樣一來,不但開發的時候每一個類會複雜,由於要兼顧其它的類,更要命的是每一個類在發生改動的時候,須要通知全部相關的類一塊兒修改,由於接口或者是功能發生了變更,使用它的地方都得變,太可怕了吧!那該如何來簡化這種多個對象之間的交互呢?

 

案例:

  使用電腦來看電影​ 爲了演示,考慮一個稍微具體點的功能。在平常生活中,咱們常用電腦來看電影,把這個過程描述出來,這裏僅僅考慮正常的狀況,也就是有主板的狀況,簡化後假定會有以下的交互過程:

  1:首先是光驅要讀取光盤上的數據,而後告訴主板,它的狀態改變了

  2:主板去獲得光驅的數據,把這些數據交給CPU進行分析處理

  3:CPU處理完後,把數據分紅了視頻數據和音頻數據,通知主板,它處理完了

  4:主板去獲得CPU處理事後的數據,分別把數據交給顯卡和聲卡,去顯示出視頻和發出聲音

​ 固然這是一個持續的、不斷重複的過程,從而造成不間斷的視頻和聲音,具體的運行過程不在討論之列,假設就有如上簡單的交互關係就能夠了。也就是說想看電影,把光盤放入光驅,光驅開始讀盤,就能夠看電影了

使用模式的解決方案

理解中介者模式

1:中介者模式的功能

  中介者的功能很是簡單,就是封裝對象之間的交互若是一個對象的操做會引發其它相關對象的變化,或者是某個操做須要引發其它對象的後續或連帶操做,而這個對象又不但願本身來處理這些關係,那麼就能夠找中介者,把全部的麻煩扔給它,只在須要的時候通知中介者,其它的就讓中介者去處理就能夠了

​ 反過來,其它的對象在操做的時候,可能會引發這個對象的變化,也能夠這麼作。最後對象之間就徹底分離了,誰都不直接跟其它對象交互,那麼相互的關係,所有被集中到中介者對象裏面了,全部的對象就只是跟中介者對象進行通訊,相互之間再也不有聯繫。​ 把全部對象之間的交互都封裝在中介者當中,無形中還獲得另一個好處,就是可以集中的控制這些對象的交互關係,這樣有什麼變化的時候,修改起來就很方便。

2:須要Mediator接口嗎

  有沒有使用Mediator接口的必要,取決因而否會提供多個不一樣的中介者實現。若是中介者實現只有一個的話,並且預計中也沒有須要擴展的要求,那麼就能夠不定義Mediator接口,讓各個同事對象直接使用中介者實現對象;若是中介者實現不僅一個,或者預計中有擴展的要求,那麼就須要定義Mediator接口,讓各個同事對象來面向中介者接口編程,而無需關心具體的中介者實現。

3:同事關係

  在中介者模式中,要求這些類都要繼承相同的類,也就是說,這些對象從某個角度講是同一個類型,算是兄弟對象。正是這些兄弟對象之間的交互關係很複雜,才產生了把這些交互關係分離出去,單獨作成中介者對象,這樣一來,這些兄弟對象就成了中介者對象眼裏的同事。

4:同事和中介者的關係

  中介者對象和同事對象之間是相互依賴的 。

5:如何實現同事和中介者的通訊

  一種實現方式是在Mediator接口中定義一個特殊的通知接口,做爲一個通用的方法,讓各個同事類來調用這個方法 。另一種實現方式是能夠採用觀察者模式,把Mediator實現成爲觀察者,而各個同事類實現成爲Subject,這樣同事類發生了改變,會通知Mediator。Mediator在接到通知事後,會與相應的同事對象進行交互。

6:中介者模式的調用順序示意圖

 

廣義中介者

標準的中介者模式在實際使用中的困難

1:是否有必要爲同事對象定義一個公共的父類?

  你們都知道,Java是單繼承的,爲了使用中介者模式,就讓這些同事對象繼承一個父類,這是很很差的;再說了,這個父類目前也沒有什麼特別的公共功能,也就是說繼承它也得不到多少好處。​ 在實際開發中,不少相互交互的對象自己是沒有公共父類的,強行加上一個父類,會讓這些對象實現起來特別彆扭。

2:同事類有必要持有中介者對象嗎?

  同事類須要知道中介者對象,以便當它們發生改變的時候,可以通知中介者對象,可是否須要做爲屬性,並經過構造方法傳入,這麼強的依賴關係呢?也能夠有簡單的方式去通知中介對象,好比把中介對象作成單例,直接在同事類的方法裏面去調用中介者對象。

3:是否須要中介者接口?

   在實際開發中,很常見的狀況是不須要中介者接口的,並且中介者對象也不須要建立不少個實例,由於中介者是用來封裝和處理同事對象的關係的,它通常是沒有狀態須要維護的,所以中介者一般能夠實現成單例。

4:中介者對象是否須要持有全部的同事?

   雖然說中介者對象須要知道全部的同事類,這樣中介者才能與它們交互。可是是否須要作爲屬性這麼強烈的依賴關係,並且中介者對象在不一樣的關係維護上,可能會須要不一樣的同事對象的實例,所以能夠在中介者處理的方法裏面去建立、或者獲取、或者從參數傳入須要的同事對象。

5:中介者對象只是提供一個公共的方法,來接受同事對象的通知嗎?

  從示例就能夠看出來,在公共方法裏,仍是要去區分究竟是誰調過來,這仍是簡單的,尚未去區分究竟是什麼樣的業務觸發調用過來的,由於不一樣的業務,引發的與其它對象的交互是不同的。​ 所以在實際開發中,一般會提供具體的業務通知方法,這樣就不用再去判斷究竟是什麼對象,具體是什麼業務了。

對標準的中介者模式在實際使用中的改進

​ 基於上面的考慮,在實際應用開發中,常常會簡化中介者模式,來使開發變得簡單,好比有以下的簡化:

1:一般會去掉同事對象的父類,這樣可讓任意的對象,只要須要相互交互,就能夠成爲同事;

2:還有一般不定義Mediator接口,把具體的中介者對象實現成爲單例;

3:另一點就是同事對象再也不持有中介者,而是在須要的時候直接獲取中介者對象並調用;中介者也再也不持有同事對象,而是在具體處理方法裏面去建立、或者獲取、或者從參數傳入須要的同事對象。​ 把這樣通過簡化、變形使用的狀況稱爲廣義中介者

廣義中介者示例——部門與人員

1:部門和人員的關係 : 是 多對多的

2:問題的出現想一想部門和人員的功能交互,舉幾個常見的功能:

(1)部門被撤銷(2)部門之間進行合併(3)人員離職(4)人員從一個部門調職到另一個部門

想一想要實現這些功能,按照前面的設計,該怎麼作呢?

(1)系統運行期間,部門被撤銷了,就意味着這個部門不存在了,但是原來這個部門下全部的人員,每一個人員的所屬部門中都有這個部門呢,那麼就須要先通知全部的人員,把這個部門從它們的所屬部門中去掉,而後才能夠清除這個部門。

(2)部門合併,是合併成一個新的部門呢,仍是把一個部門併入到另外一個部門?若是是合併成一個新的部門,那麼須要把原有的兩個部門撤銷,而後再新增一個部門;若是是把一個部門合併到另外一個部門裏面,那就是撤銷掉一個部門,而後把這個部門下的人員移動到這個部門。無論是那種狀況,都面臨着須要通知相應的人員進行更改這樣的問題

(3)人員離職了,反過來就須要通知他所屬於的部門,從部門的擁有人員的記錄中去除掉這我的員。

(4)人員調職,一樣須要通知相關的部門,先從原來的部門中去除掉,而後再到新的部門中添加上。

看了上述的描述,感受如何?

  麻煩的根源在什麼地方呢?仔細想一想,對了,麻煩的根源就在於部門和人員之間的耦合,這樣致使操做人員的時候,須要操做全部相關的部門,而操做部門的時候又須要操做全部相關的人員,使得部門和人員攪和在了一塊兒。

3:中介者來解決

  找到了根源就好辦了,採用中介者模式,引入一箇中介者對象來管理部門和人員之間的關係,就能解決這些問題了。​ 若是採用標準的中介者模式,想一想上面提出的那些問題點吧,就知道實現起來會很彆扭。所以採用廣義的中介者來解決,這樣部門和人員就徹底解耦了,也就是說部門不知道人員,人員也不知道部門,它們徹底分開,它們之間的關係就徹底由中介者對象來管理了。

 

 

中介者模式的優缺點

1:鬆散耦合

​ 適當地使用中介者模式能夠避免同事類之間的過分耦合,使得各同事類之間能夠相對獨立地使用。

2:集中控制交互

​ 使用中介者模式能夠將對象的行爲和協做進行抽象,可以比較靈活的處理對象間的相互做用

3:多對多變成一對多

​ 使用中介者模式能夠將對象間一對多的關聯轉變爲一對一的關聯,使對象間的關係易於理解和維護。

4:過分集中化

思考中介者模式

中介者模式的本質是:封裝交互

什麼時候選用中介者模式

1:若是一組對象之間的通訊方式比較複雜,致使相互依賴、結構混亂,能夠採用中介者模式,把這些對象相互的交互管理起來,各個對象都只須要和中介者交互,從而使得各個對象鬆散耦合,結構也更清晰易懂

2:若是一個對象引用不少的對象,並直接跟這些對象交互,致使難以複用該對象。能夠採用中介者模式,把這個對象跟其它對象的交互封裝到中介者對象裏面,這個對象就只須要和中介者對象交互就能夠了

​   在面向對象編程中,一個類必然會與其餘的類發生依賴關係,徹底獨立的類是沒有意義的。一個類同時依賴多個類的狀況也至關廣泛,既然存在這樣的狀況,說明,一對多的依賴關係有它的合理性,適當的使用中介者模式可使本來凌亂的對象關係清晰,可是若是濫用,則可能會帶來反的效果。通常來講,只有對於那種同事類之間是網狀結構的關係,纔會考慮使用中介者模式。能夠將網狀結構變爲星狀結構,使同事類之間的關係變的清晰一些。

​   中介者模式是一種比較經常使用的模式,也是一種比較容易被濫用的模式。對於大多數的狀況,同事類之間的關係不會複雜到混亂不堪的網狀結構,所以,大多數狀況下,將對象間的依賴關係封裝的同事類內部就能夠的,沒有必要非引入中介者模式。濫用中介者模式,只會讓事情變的更復雜。

 代碼地址: https://gitee.com/weixiaotao1992/DesignPatternsForJava

相關文章
相關標籤/搜索