面向對象的可復用設計模式之中介者模式(18/24)

小智雅匯 發佈 2020-02-06T16:03:24+00:00

那麼多的國家,國家之間的關係及其複雜;就好比現在,美國和中國有經濟利益關係,美國和日本有盟友關係,朝鮮和中國有說不清道不明的關係;這些複雜的關係,稍微處理不好,就可能引發局部戰爭,更有可能引發第三次世界大戰。

中介者模式(Mediator pattern) 能集中相關對象之間複雜的溝通和控制方式。

我們都知道,國際政治是一門很深的學問,不玩政治的人是搞不懂的。那麼多的國家,國家之間的關係及其複雜;就好比現在,美國和中國有經濟利益關係,美國和日本有盟友關係,朝鮮和中國有說不清道不明的關係;這些複雜的關係,稍微處理不好,就可能引發局部戰爭,更有可能引發第三次世界大戰。如果國與國之間出現了利益糾紛,那麼該怎麼辦呢?這個時候,聯合國出現了。聯合國就是一個處理國與國之間糾紛的中介者。

在聯合國還沒有成立時,國與國之間的關係是這樣的:


當聯合國成立以後,國與國之間出現糾紛時,是這樣的:

聯合國的成立,讓很多關係簡單化了,讓問題的處理也簡單化了,使國與國之間因為糾紛產生摩擦的幾率減小了,讓世界更和平了。

用一個中介對象來封裝一系列的對象交互。中介者使各對象不需要顯式地相互引用,從而使其耦合鬆散,而且可以獨立地改變它們之間的交互。

中介者作為一種行為設計模式,它公開一個統一的接口,系統的不同對象或組件可以通過該接口進行通信。增加一個中介者對象後,所有的相關對象通過中介者對象來通信,而不是互相引用,所以當一個對象發生改變時,只需要通知中介者對象即可。

Mediator:中介者,它定義了一個接口用於與各個Colleague對象通信;

ConcreteMediator:具體的中介者,它通過協調各Colleague對象實現協作行為;並了解和維護它的各個Colleague;

Colleague:同事類,每一個同事類都知道它的中介者對象;每一個同事對象在需要與其他的同事通信的時候,不是直接通信,而是與它的中介者通信。

它們之間是按照以下方式進行協作的:

同事向一個中介者對象發送和接收請求。中介者在各同事間適當地轉發請求以實現協作行為。

#include <iostream>
using namespace std;

#define SAFE_DELETE(p) if (p) { delete p; p = NULL; }

class Mediator;

class Colleague
{
public:
     Colleague(Mediator *pMediator) : m_pMediator(pMediator){}

     virtual void Send(wchar_t *message) = 0;

protected:
     Mediator *m_pMediator;
};

class ConcreteColleague1 : public Colleague
{
public:
     ConcreteColleague1(Mediator *pMediator) : Colleague(pMediator){}

     void Send(wchar_t *message);

     void Notify(wchar_t *message)
     {
          wcout<<message<<endl;
     }
};

class ConcreteColleague2 : public Colleague
{
public:
     ConcreteColleague2(Mediator *pMediator) : Colleague(pMediator){}

     void Send(wchar_t *message);

     void Notify(wchar_t *message)
     {
          cout<<"ConcreteColleague2 is handling the message."<<endl;
          wcout<<message<<endl;
     }
};

class Mediator
{
public:
     virtual void Sent(wchar_t *message, Colleague *pColleague) = 0;
};

class ConcreteMediator : public Mediator
{
public:
     // The mediator forward the message
     void Sent(wchar_t *message, Colleague *pColleague)
     {
          ConcreteColleague1 *pConcreteColleague1 = 
                     dynamic_cast<ConcreteColleague1 *>(pColleague);
          if (pConcreteColleague1)
          {
               cout<<"The message is from ConcreteColleague1. "
                      <<"Now mediator forward it to ConcreteColleague2"<<endl;
               if (m_pColleague2)
               {
                    m_pColleague2->Notify(message);
               }
          }
          else
          {
               if (m_pColleague1)
               {
                    m_pColleague1->Notify(message);
               }
          }
     }

     void SetColleague1(Colleague *pColleague)
     {
          m_pColleague1 = dynamic_cast<ConcreteColleague1 *>(pColleague);
     }

     void SetColleague2(Colleague *pColleague)
     {
          m_pColleague2 = dynamic_cast<ConcreteColleague2 *>(pColleague);
     }

private:
     // The Mediator knows all the Colleague
     ConcreteColleague1 *m_pColleague1;
     ConcreteColleague2 *m_pColleague2;
};

void ConcreteColleague1::Send(wchar_t *message)
{
     // The second parameter mark where the message comes from
     m_pMediator->Sent(message, this);
}

void ConcreteColleague2::Send(wchar_t *message)
{
     m_pMediator->Sent(message, this);
}

int main()
{
     // Create the mediator
     Mediator *pMediator = new ConcreteMediator();

     Colleague *pColleague1 = new ConcreteColleague1(pMediator);
     Colleague *pColleague2 = new ConcreteColleague2(pMediator);

     ConcreteMediator *pConcreteMediator = dynamic_cast<ConcreteMediator *>(pMediator);
     pConcreteMediator->SetColleague1(pColleague1);
     pConcreteMediator->SetColleague2(pColleague2);

     wchar_t message[260] = L"Where are you from?";
     pColleague1->Send(message);

     return 0;
}

Output:

The message is from ConcreteColleague1. Now mediator forward it to ConcreteColleague2
ConcreteColleague2 is handling the message.
Where are you from?

1 使用場合

一組對象以定義良好但是複雜的方式進行通信。產生的相互依賴關係結構混亂且難以理解;

一個對象引用其他很多對象並且直接與這些對象通信,導致難以復用該對象;

想定製一個分布在多個類中的行為,而又不想生成太多的子類。

2 優缺點

減少了子類生成,Mediator將原本分布於多個對象間的行為集中在一起。改變這些行為只需生成Meditator的子類即可。這樣各個Colleague類可被重用;

它將各Colleague解耦,Mediator有利於各Colleague間的松耦合。你可以獨立的改變和復用各Colleague類和Mediator類;

它簡化了對象協議,用Mediator和Colleague間的一對多的交互來代替多對多的交互。一對多的關係更容易理解、維護和擴展;

它對對象如何協作進行了抽象,將中介作為一個獨立的概念並將其封裝在一個對象中,使你將注意力從對象各自本身的行為轉移到它們之間的交互上來。這有助於弄清楚一個系統中的對象是如何交互的;

它使控制集中化,中介者模式將交互的複雜性變為中介者的複雜性。因為中介者封裝了協議,它可能變得比任一個Colleague都複雜。這可能使得中介者自身成為一個難於維護的龐然大物。

3 與外觀模式的區別

我在看中介者模式時,第一眼就感覺中介者模式和外觀模式超級像。外觀模式與中介者模式的不同之處在於它是對一個對象子系統進行抽象,從而提供了一個更為方便的接口;外觀模式的協議是單向的,即外觀模式向子系統提出請求,但反過來則不行;而對於中介者模式,是進行多個對象之間的協作,通信是多向的。

-End-

關鍵字: