这篇文章比较短,修改自 写给大家看的设计模式之中介者中的例子
中介者模式的定义和目的自不必说, 参考上文即可. 本文针对实现方式做一个补充.
中介者模式增加了一个第三方对象(中介者)来控制两个对象(同事)间的交互. 有助于对彼此通信的解耦, 毕竟他们并不需要关心对方的实现细节.
例子中给出了ChatRoom
作为第三方中介者, 而User
作为真正的通信对象, 每个用户发送的消息实际上是在ChatRoom
中进行了广播. 对于通信的接耦有两种方式:
-
User
调用第三方对象的方法, 进行消息或者动作的传递, 比如上文中的实现即调用了ChatRoom
的ShowMessage
方法. - 不同的对象不通过方法调用来交互, 而是通过消息总线传递消息体.
实现
这里针对第二点给出实现, 这里利用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
通信,互相调用来调用去,很容易晕掉, 而只用通过订阅事件进行的数据传递,数据生产者和使用者在注册的时候就清晰明了,不容易出错.