这篇文章比较短,修改自 写给大家看的设计模式之中介者中的例子
中介者模式的定义和目的自不必说, 参考上文即可. 本文针对实现方式做一个补充.

中介者模式增加了一个第三方对象(中介者)来控制两个对象(同事)间的交互. 有助于对彼此通信的解耦, 毕竟他们并不需要关心对方的实现细节.

例子中给出了ChatRoom作为第三方中介者, 而User作为真正的通信对象, 每个用户发送的消息实际上是在ChatRoom中进行了广播. 对于通信的接耦有两种方式:

  • User调用第三方对象的方法, 进行消息或者动作的传递, 比如上文中的实现即调用了ChatRoomShowMessage方法.
  • 不同的对象不通过方法调用来交互, 而是通过消息总线传递消息体.

实现

这里针对第二点给出实现, 这里利用boost::signal2来实现ChatRoom对消息体订阅, 各User对象实例负责信息的发布.

#include <iostream>
#include <string>
#include <ctime>
#include <iomanip>
#include <boost/signals2/signal.hpp>
using namespace std;
using namespace boost::signals2;

// Message
struct EventMessage {
    virtual ~EventMessage() = default;
    virtual void showMessage() const = 0;
};
struct ChatMessage : public EventMessage {
    string username;
    string message;
    ChatMessage(const string &username, const string &message) : username(username), message(message) {}

    void showMessage() const override {
        std::time_t now = std::time(nullptr);
        std::cout << std::put_time(std::localtime(&now), "%Y-%m-%d %H:%M:%S") << "[" << username << "]: " << message << std::endl;
    }
};

// EventBus -> ChatRoom
struct EventBus {
    signal<void(EventMessage *)> sig;
    EventBus() {
        sig.connect([](EventMessage *e){
            ChatMessage *mess = dynamic_cast<ChatMessage *>(e);
            if(mess) {
                mess->showMessage();
            }});
    }
};

// instance
struct User {
    string   name_;
    EventBus &event;

    User(const string &name_, EventBus &event) : name_(name_), event(event) {
    }

    void send(const string &message) {
        ChatMessage chatMessage(name_, message);
        event.sig(&chatMessage);
    }
};

int main() {
    EventBus bus;
    User john("John Doe", bus);
    User jane("Jane Doe", bus);

    john.send("Hi, there!");
    jane.send("Hey!");
}

优点

当前的例子的业务模型实际比较简单, 如果业务变的复杂(比如还要支持私信即可定点sendMessage新增广播消息即每个用户需要支持received), 如果继续使用方法传递,那么ChatRoom为了和User通信,互相调用来调用去,很容易晕掉, 而只用通过订阅事件进行的数据传递,数据生产者和使用者在注册的时候就清晰明了,不容易出错.


Ender
599 声望17 粉丝