018.设计模式之Mediator 模式

 一、概述
Mediator(中介者)模式的名称已经基本能够反映该模式的意图:用一个中介对象来封装一系列的对象之间的交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。Mediator很象十字路口的红绿灯,每个车辆只需和红绿灯交互,而不是在各车辆之间进行交互。

Mediator与Proxy的比较
Proxy模式是简化的Mediator模式?
个人认为从功能上讲,Mediator模式与Proxy模式存在一定的相似性,但Proxy主要在于控制对被访问对象的访问,这种访问往往是单向的,而Mediator模式则在于为系统内不同的对象之间的访问提供一种媒介,这种访问往往是多向的。

Mediator与Facade的比较
很多设计模式的书中都会将Mediator模式与Facade模式进行比较,个人认为二者的区别十分明显:一个是为整个子系统对外提供一个简单化的接口,子系统的内部可能十分复杂,很多类交互作用才形成了最终的简单化的统一接口;而Mediator模式则作为系统内多个对象交互的“媒介”,负责封装对象间的交互,所有对象只需要与Mediator类交互,而不是相互之间直线联系。所以,也许在实现Facade模式时在子系统的内部采用Mediator模式可能是个不错的选择。

二、结构
Mediator模式的结构如下图所示:

1、Mediator模式类图示意
上面的类图并不能完全反映Mediator模式的全部思想,下面结合GoF的DP一书中的一个对象图对此进行深入说明:

2、一个典型的使用Mediator模式的对象图
在上面的类图中,各角色的分工如下:
1
、Mediator(中介者):中介者定义一个接口用于与各Colleague(同事)对象通信。
2
、ConcreteMediator(具体中介者):具体中介者通过协调各同事对象实现协作行为,并了解和维护它的各个同事。
3
、Colleague  class(同事类):每一个同事类都知道它的中介者对象,每一个同事对象在需与其他的同事通信的时候,与它的中介者通信。

三、应用
各个对象之间的交互操作非常多,每个对象的行为操作都依赖彼此对方,修改一个对象的行为,同时会涉及到修改很多其他对象的行为,如果使用Mediator模式,可以使各个对象间的耦合松散,只需关心和 Mediator的关系,使多对多的关系变成了一对多的关系,可以降低系统的复杂性,提高可修改扩展性。

在下列情况下使用中介者模式 :
1
、一组对象以定义良好但是复杂的方式进行通信。产生的相互依赖关系结构混乱且难以理解。
2
、一个对象引用其他很多对象并且直接与这些对象通信 ,导致难以复用该对象。
3
、想定制一个分布在多个类中的行为,而又不想生成太多的子类。

四、优缺点
Mediator模式有以下优点和缺点 :
1
、减少了子类生成Mediator将原本分布于多个对象间的行为集中在一起,改变这些行为只需生成Mediator的子类即可,这样各个Colleague类可被重用。
2
、它将各Colleague解耦。Mediator有利于各Colleague间的松耦合,你可以独立的改变和复用各Colleague类和Mediator类。
3
、它简化了对象协议用Mediator和各Colleague间的一对多的交互来代替多对多的交互。一对多的关系更易于理解、维护和扩展。
4
、它对对象如何协作进行了抽象将中介作为一个独立的概念并将其封装在一个对象中,使你将注意力从对象各自本身的行为转移到它们之间的交互上来。这有助于弄清楚一个系统中的对象是如何交互的。
5
、它使控制集中化中介者模式将交互的复杂性变为中介者的复杂性。因为中介者封装了协议,它可能变得比任一个Colleague都复杂。这可能使得中介者自身成为一个难于维护的庞然大物。

五、举例
Mediator模式是GoF的 23种设计模式中较为容易理解的一个,我们在平时的应用中也会经常用到,但可能不会有意去抽象出一个完整的Mediator类,因为要设计一个可复用又可扩展的Mediator是很不容易的。如在MFC的文档 /视图程序中,我们可能会在CWinApp派生类中添加一些供所有线程共享的数据成员或方法,这样,各线程即可通过与theApp进行交互即可达到影响其它线程的目的,在这里,CWinApp一定程度上扮演了Mediator的角色。

有人称MFC程序中Dialog在各控件间扮演着Mediator的角色,认为各控件实现时无需知道其它控件,只是将消息发送给父窗口Dialog来处理,而Dialog负责在消息处理函数中完成各控件之间的信息交互,使得控件间复杂的耦合关系变成简单的控件 -Mediator(Dialog)关系。我并非十分赞同这种观点,因为我们往往将控件作为整个Dialog的一个组成部分来看待,而有意无意地忽略了它本身也是一个独立对象的事实,造成这种现象的一个关键原因可能在于MFC的消息映射机制屏蔽了控件将消息发送给对话框的过程,使得我们更愿意去认为消息是Dialog(处理)的消息,而不是(来自)控件的消息。
在Java应用中,以上状况依然存在,但是由于没有了直接的消息映射支持,JDialog往往更容易表现得像一个Mediator。
此外,还有一个观点认为,Java的Container通过选择一定的LayoutManager策略(Strategy,后面的笔记中将讲到),在各控件间起到了Mediator的作用,当新的Component被加到Container,如JPanel中时,必然会对其它控件的Layout(布局)造成影响,但各控件间是不知道对方的,他们只需知道自己的Parent Window,然后与之交互即可。这种观点也有欠妥当,但从Mediator作为各object之间的交互的媒介这一实质来看,也无可厚非。

简而言之,Mediator模式的主要作用在于为多个对象之间的交互提供一种媒介,以简化对象之间的耦合关系。下面用两个实例来说明Mediator模式的应用:
1
、ChatRoom:
聊天室大家想必都知道,在下面的示例中,我们尝试实现一个布告栏式的ChatRoom,任何人想要发送消息给其他人,只需将消息发送给ChatRoom对象,由ChatRoom负责数据的转发,而不是直接与消息的接收者交互。后面的笔记中将从Observer模式的角度来解决ChatRoom问题。

#include <iostream>
#include <string>
#include <map>
using namespace std ;

class
 Participant ;

// "AbstractMediator"
struct IChatroom
{

  // Methods
  virtual  void Register ( Participant * participant  ) =  0 ;
  virtual
 void Send ( string & from , string & to , string & message  ) =  0 ;
};


// "AbstractColleague"
class Participant
{

    friend class
 Chatroom ;
    // Fields
private :
    IChatroom * pChatroom ;
    string name ;

    // Constructors
public :
    /*Participant()
    {
    }*/


    Participant (  const  char * name  )
    {

        this
->name  = name ;
    }


    virtual
 ~Participant ()
    {
    }


    // Methods
    virtual  void Send ( string & to , string & message  )
    {

        pChatroom ->Send ( name , to , message  );
    }


    virtual
 void Receive ( string & from , string & message  )
    {

        cout  << from .c_str () <<  " to "  << name .c_str () <<  " : ["  << message .c_str () <<  "]"  << endl ;
    }
};


// More ConcreteColleague, omitted...

// "ConcreteMediator"
class Chatroom  :  public IChatroom
{

    // Fields
private :
    map <string , Participant *> mapParticipants ;     // nickname to Participant map

    // Methods
public :
    void
 Register ( Participant * pParticipant  )
    {

        mapParticipants [ pParticipant ->name  ] = pParticipant ;

        pParticipant ->pChatroom  =  this ;
    }


    void
 Send ( string & from , string & to , string & message  )
    {

        map <string , Participant *>::iterator ptr ;
        ptr  = mapParticipants .find (to );
        if
 ( ptr  != mapParticipants .end () )
        {

            Participant * pto  = (*ptr ).second ;
            pto ->Receive ( from , message  );
        }
    }
};


int
 main ()
{

    // Create chatroom
    Chatroom c ;

    // Create 'chatters' and register them
    Participant George ( "George" );
    Participant Paul ( "Paul" );
    Participant Ringo ( "Ringo" );

    c .Register ( &George  );
    c .Register ( &Paul  );
    c .Register ( &Ringo  );

    // Chatting participants
    George .Send ( string ( "Paul" ), string ( "Hi Paul!" ) );
    Paul .Send ( string ( "Ringo" ), string ( "Good Morning!" ) );
    Ringo .Send ( string ( "George" ), string ( "Hi Friend!" ) );

    return
 0 ;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值