中介者(Mediator)

中介者模式属于设计模式::行为模式的一种,特别的,属于行为对象模式

行为模式涉及到算法和对象间职责的分配。行为模式不仅描述对象或类的模式,还描述他们之间的通信模式(协作)。

行为模式分为两种:

  • 行为类模式:使用继承机制在类间分配行为。
  • 行为对象模式:使用对象复合而不是继承。

一言以蔽之

引入一个中间对象(中介),解决对象间的(双向)依赖,避免紧耦合(接口隔离)。

注:门面模式(Facade)解决系统间单向的依赖。

举例

/*
 * 窗口对话框的基类
 */
class Director{
public:
    virtual ~Director();
    virtual void WidgetChanged(Widget*) = 0;

protected:
    Director();
    virtual void CreateWidgets() = 0;
}

/*
 * 控件的基类
 */
class Widget{
public:
    Widget(Director*);
    virtual void Changed(){
        // 在这里调用Director的接口方法,Director的子类为窗口
        _director->WidgetChanged();     
    }

    // 规范接口
    virtual void HandleMouseEvent(MouseEvent& event); 
private:
    Director* _director;
}

class ListBox : public Widget{
public:
    ListBox(Director*);

    virtual const char* GetSelection();
    virtual void SetList(List<char*>* listItems);

    virtual void HandleMouseEvent(MouseEvent& event) override{}
}

class EntryField : public Widget{
public:
    EntryField(Director*);

    virtual const char* GetText();
    virtual void SetText(const char* text);
    
    virtual void HandleMouseEvent(MouseEvent& event) override {}
}

class Button : public Widget{
public:
    Button(Director*);

    virtual void SetText(const char* text);
    
    virtual void HandleMouseEvent(MouseEvent& event) override {
        // ...
        Changed();   // 基类方法
    }
}

/*
 * 使用控件组装对话框,这个就是中介者(沟通各个控件)
 */
class FontDirector : public Director{
public:
    FontDirector();
    virtual ~FontDirector();

    // 保证窗口组件正确协同工作
    virtual void WidgetChanged(Widget* theChangedWidget) override{
        if (theChangedWidget == _fontListBox) {
            _fontNameField->SetText(_fontListBox->GetSelection());
        } else if (theChangedWidget == _okButton){
            // ...
        } else if (theChangedWidget == _cancelButton){
            // ...
        } 
    }

protected:
    virtual void CreateWidgets() override{
        _okButton = new Button(this);
        //...
        // 把这些控件放到对话框中
    }

private:
    Button* _okButton;
    Button* _cancelButton;
    ListBox* _fontListBox;
    EntryField* _fontNameField;
}

注意事项

中介者中的M需要一种消息通知的规范,好与所有的依赖对象进行沟通。

  1. Widget::Changed(),Widget的子类可以调用此方法与FontDirector对象进行沟通,通知FontDirector进行更新界面。
  2. Widget::HandleMouseEvent()=0,应用程序需要把系统事件(如鼠标点击事件)分发给应用程序内不同的GUI对象,这里实现事件循环的对象(分发系统事件的对象,如EventDispatch类)也是一个中介者,而HandleMouseEvent就是一个消息接口规范。

混合模式:中介者+观察者

  • 观察者模式:有Event的时候通知Observer,可以有多个Observer。比如QT中的:(继承QObejct的时候会注册)
    void paintEvent(QPaintEvent *) override;
    void mouseMoveEvent(QMouseEvent *) override;
  • 中介者模式:使用EventDispatch类处理Event与Event之间的处理逻辑。

使用场景

数据绑定类型:同时依赖界面元素、数据模型

数据模型改变,绑定的对象(可以理解为中介者)就得到消息,去更改界面元素

中介者与观察者的区别

  1. 都是行为对象模式(对象行为模式)。
  2. 中介者强调是多个类(同事类)之间的交互,多对多,通过一个中介者来交互。
  3. 观察者强调一对多的关系,一个变化,其他都变化

相关模式

  1. 门面模式(Facade)
  2. 观察者模式(Observer)