行为型模式--中介者

1、意图

  用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

2、结构

  

 

 

 3、参与者

  Mediator:中介者定义一个接口用于与各同事对象通信。

  ConcreteMediator:具体中介者,通过协调各同事对象实现协作行为;了解并维护它的各个同事;

  Colleague class:同事类,每一个同事类都知道它的中介者对象;每一个同事对象在需与其他的同事通信的时候,与它的中介者通信。

4、适用性

  在以下情况使用中介者模式:

  一组对象以定义良好但是复杂的方式进行通信。产生的相互依赖关系结构混乱且难以理解;

  一个对象引用其他很多对象并且直接与这些对象通信,导致难以复用该对象;

  想定制一个分布在多个类中的行为,而又不想生成太多的子类。

5、代码示例

  场景:考虑一个图形用户界面中对话框的实现。对话框使用一个窗口来展现一系列的窗口组件,如按钮、菜单和输入域等。

  通常对话框中的窗口组件间存在依赖关系。例如,当一个特定的输入域为空时,某个按钮不能使用;在称为列表框的一列选项中选择一个表目可能会改变一个输入域的内容;反过来,在输入域中输入正文可能会自动的选择一个或多个列表框中相应的表目;

  不同的对话框会有不同的窗口组件间的依赖关系。因此即使对话框显示相同类型的窗口组件,也不能简单地直接重用已有的窗口组件类;而必须定制它们以反映特定对话框的依赖关系。由于涉及很多个类,用逐个生成子类的办法来定制它们会很冗长。

  可以通过将集体行为封装在一个单独的中介者(mediator)对象中以避免这个问题。中介者负责控制和协调一组对象间的交互。中介者充当一个中介以使组中的对象不再相互显式引用。这些对象仅知道中介者,从而减少了相互连接的数目。

// 使用一个DialogDirector来实现字体对话框。抽象类DialogDirector为中介者,定义了一个接口。
class DialogDirector
{
public:
    virtual ~DialogDirector(); 
    virtual void ShowDialog(); 
    virtual void widgetChanged(widget*) = 0; 
protected:
    DialogDirector(); 
    virtual void Createwidgets()=0;
}; 

// Widget是窗口组件的抽象基类。一个窗口组件应该知道它的中介者。
class widget
{
public:
    widget(DialogDirector*); 
    virtual void Changed(); 
    virtual void HandleMouse(MouseEvent& event); 
private:
    DialogDirector* director;
};

// Changed调用中介者的WidgetChanged操作。通知中介某个重要事件发生了。
void widget::Changed ()
{
    _director->widgetChanged(this);
}
// ListBox、EntryField和Button是Widget的子类,用作特定的用户界面构成元素。
// ListBox提供了一个GetSelection操作来得到当前的选择项,而EntryField的SetText操作则将新的正文放入该域中。
class ListBox : public widget
{
public:
    ListBox(DialogDirector*); 
    virtual const char* Getselection(); 
    virtual void SetList(List<char*>* listItems); 
    virtual void HandleMouse(MouseEvent& event);
};

class EntryField : public widget
{
public:
    EntryField(DialogDirector*); 
    virtual void SetText(const char* text); 
    virtual const char* GetText(); 
    virtual void HandleMouse(MouseEvent& event);
    // ...
};

// Button是一个简单的窗口组件,它一旦被按下就调用Changed。这是在其HandleMouse的实现中完成的:
class Button : public widget
{
public:
    Button(DialogDirector*); 
    virtual void SetText(const char* text); 
    virtual void HandleMouse(MouseEvent& event);
    //...
};
void Button::HandleMouse (MouseEvent& event)
{
    // ...
    Changed(); 
}
// FontDialogDirectator类在对话框中的窗口组件间进行中介。FontDialogDirectator是DialogDirector的子类:
class FontDialogDirector : public DialogDirector
{
public:
    FontDialogDirector(); 
    virtual ~FontDialogDirector(); 
    virtual void widgetchanged(widget*); 
protected:
    virtual void Createwidgets(); 
private:
    Button* _ok; 
    Button* _cancel; 
    ListBox* _fontList; 
    EntryField* _fontName;
};

// FontDialogDirector跟踪它显示的窗口组件。它重定义CreateWidgets以创建窗口组件并初始化对它们的引用:
void FontDialogDirector::Createwidgets ()
{
    _ok = new Button(this);
    _cancel = new Button(this);
    _fontList = new ListBox(this);
    _fontName = new EntryField(this);
    // fill the listBox with the available font names
    // assemble the widgets in the dialog
}

// WidgetChanged保证窗口组件正确地协同工作:
void FontDialogDirector::widgetChanged(widget* thechangedwidget)
{
    if (theChangedwidget ==_fontList)
    {
        _fontName->SetText (_fontList->GetSelection());
    }
    else if (thechangedwidget == _ok)
    {
        // apply font change and dismiss dialog
        // ...
    }
    else if (theChangedwidget == _cancel)
    {
        // dismiss dialog
    }
}

6、总结

  中介者模式主要解决多个协同工作的对象之间的相互依赖关系导致的结构混乱、难以复用问题。

  中介者模式通过一个中介者对象引用其他对象并且与这些对象相互通信的方式,解耦多个复杂对象之间的相互依赖关系。采用一对多的交互来代替多对多。

  各个对象之间的协同行为,可以用不同的中介者对象来控制集中,改变对象间的行为仅需生成中介者对象的子类即可。

  中介者模式将对象间交互的复杂性转移到中介者上,中介者复杂且较难维护。

posted @ 2022-05-04 14:31  流翎  阅读(50)  评论(0编辑  收藏  举报