中介者模式

一、簡介
1. 定義
用一箇中介對象來封裝一系列的對象交互。中介者使各對象不需要顯式地相互引用,從而使其耦合鬆散,而且可以獨立地改變它們之間的交互。
2. 應用場景
適用於系統中大量的對象需要相互的依賴,並且彼此間的依賴關係複雜混亂,此時在重構過程中,可以用一箇中間類來管理這些對象之間的依賴關係。
3.優缺點
優點:
將多個互相依賴的類進行解耦,使得這些有交互的對象鬆耦合;
增加交互對象時,只需要在中介類中進行修改即可,不需要變動其他的對象實現;
缺點:
中介類可能會變得複雜,甚至會發展到功能龐大,違反類的單一職責。
4. 類圖


二、 代碼示例
1. 場景簡介
在組隊槍戰遊戲中,突擊小隊需要通過通訊設備來完成戰術的安排與實施,隊長主要負責下達命令,隊員根據戰況請求支援。

#ifndef MEDIATOR_H
#define MEDIATOR_H

#include <QString>
#include <QDebug>
#include <QMap>

class IMediator;

class IUser
{
public:
    IUser(QString name)
        : m_name(name)
    {};
    virtual ~IUser() {};

    inline QString name() { return m_name; };
    virtual void send(QString msg, IMediator *mediator) = 0;
    virtual void notify(QString msg) = 0;

private:
    QString            m_name;
};

class IMediator
{
public:
    IMediator() {};
    virtual ~IMediator() {};

    virtual void registeUser(IUser *user)
    {
        QString name = user->name();
        if (!m_userMap.contains(name))
        {
            m_userMap.insert(name, user);
        }
    };
    virtual void unregisterUser(IUser *user)
    {
        m_userMap.remove(user->name());
    };
    virtual void sendMsg(QString msg, IUser *sender) = 0;

protected:
    QMap<QString, IUser*>        m_userMap;
};

class GameMediator : public IMediator
{
public:
    GameMediator() {};
    virtual ~GameMediator() {};

    virtual void sendMsg(QString msg, IUser *sender)
    {
        foreach (IUser* user, m_userMap)
        {
            if (user->name() != sender->name())
            {
                user->notify(msg);
            }
        }
    };
};

class UserImp : public IUser
{
public:
    UserImp(QString name)
        : IUser(name)
    {};
    virtual ~UserImp() {};

    virtual void send(QString msg, IMediator *mediator)
    {
        if (nullptr != mediator)
        {
            mediator->sendMsg(msg, this);
        }
    };
    virtual void notify(QString msg)
    {
        qDebug() << name() << "receive msg: " << msg;
    };
};

#if 1

#define FREE_OBJ(obj)        if (nullptr != (obj)){delete (obj); (obj) = nullptr;}

void main()
{
    IMediator *mediator = new GameMediator;

    UserImp *captain = new UserImp("Game Captain");
    UserImp *playerA = new UserImp("XiaoMing");
    UserImp *playerB = new UserImp("XiaoQiang");

    mediator->registeUser(captain);
    mediator->registeUser(playerA);
    mediator->registeUser(playerB);

    captain->send("Ready?", mediator);

    playerA->send("Help!", mediator);

    FREE_OBJ(mediator);
    FREE_OBJ(captain);
    FREE_OBJ(playerA);
    FREE_OBJ(playerB);

    getchar();
}

#endif // 1

#endif // !MEDIATOR_H