Skip to content

中介者模式

回到目录

简介

参考链接

中介者模式是一种行为设计模式,当一个项目中模块比较多的时候,如果模块之间交互很多,很复杂的时候,可以考虑用中介者模式,每个模块都通过中介者进行交互,各个模块之间不会有耦合。实现了一种类与类之间的交互方式。

MVC 框架,其中C(控制器)就是 M(模型)和 V(视图)的中介者。

UML类图

代码示例

#include <iostream>

class Mediator;
class IUser;

class IMediator {
public:
  virtual void set_user1(IUser *user) = 0;
  virtual void set_user2(IUser *user) = 0;
  virtual void transmit(const std::string &msg, IUser *user) = 0;
};

class IUser {
public:
  IUser(IMediator *m): mediator(m) {}
  void send(const std::string &msg) {
    mediator->transmit(msg, this);
  }

  virtual void recv(const std::string &msg) = 0;

  IMediator *mediator = nullptr;
};

class User1: public IUser {
public:
  User1(IMediator *m): IUser(m) {}
  virtual void recv(const std::string &msg) {
    std::cout << "User1 recv msg: " << msg << std::endl;
  }
};
class User2: public IUser {
public:
  User2(IMediator *m): IUser(m) {}
  virtual void recv(const std::string &msg) {
    std::cout << "User2 recv msg: " << msg << std::endl;
  }
};

class Mediator: public IMediator {
public:
  virtual void set_user1(IUser *user) {
    user1 = user;
  }
  virtual void set_user2(IUser *user) {
    user2 = user;
  }
  virtual void transmit(const std::string &msg, IUser *user) {
    if (user == user1) {
      user2->recv(msg);
    } else if(user == user2) {
      user1->recv(msg);
    }
  }

  IUser *user1 = nullptr;
  IUser *user2 = nullptr;
};

int main() {
  IMediator *mediator = new Mediator();
  IUser *user1 = new User1(mediator);
  IUser *user2 = new User2(mediator);
  mediator->set_user1(user1);
  mediator->set_user2(user2);

  user1->send("Hello");
  user2->send("Hello");
  user1->send("Hello");
  user1->send("Hello");

  delete user1;
  delete user2;
  delete mediator;
}

/*
run result:
User2 recv msg: Hello
User1 recv msg: Hello
User2 recv msg: Hello
User2 recv msg: Hello
*/

例子二

#include <iostream>

class Mediator;
class IUser;

// 中介者接口类
class IMediator {
public:
  virtual void transmit(const std::string &msg, IUser *user) = 0;
};

// 模块user抽象类
class IUser {
public:
  IUser() {}
  void send(const std::string &msg) {
    mediator_->transmit(msg, this);
  }
  virtual void set_mediator(IMediator *mediator) {
    mediator_ = mediator;
  }
  virtual void recv(const std::string &msg) = 0;

  IMediator *mediator_ = nullptr;
};

// 具体user1
class User1: public IUser {
public:
  User1() {}
  virtual void recv(const std::string &msg) {
    std::cout << "User1 recv msg: " << msg << std::endl;
  }
};
// 具体user2
class User2: public IUser {
public:
  User2() {}
  virtual void recv(const std::string &msg) {
    std::cout << "User2 recv msg: " << msg << std::endl;
  }
};

// 具体中介者类
class Mediator: public IMediator {
public:
  Mediator(IUser *user1, IUser *user2): user1_(user1), user2_(user2) {
    user1_->set_mediator(this);
    user2_->set_mediator(this);
  }
  // transmit 实现每个模块的交互
  // user1->send==>user2->revv
  // user2->send==>user1->revv
  virtual void transmit(const std::string &msg, IUser *user) {
    if (user == user1_) {
      user2_->recv(msg);
    } else if(user == user2_) {
      user1_->recv(msg);
    }
  }

  IUser *user1_ = nullptr;
  IUser *user2_ = nullptr;
};

int main() {
  IUser *user1 = new User1();
  IUser *user2 = new User2();
  IMediator *mediator = new Mediator(user1, user2);

  user1->send("Hello");
  user2->send("Hello");
  user1->send("Hello");
  user1->send("Hello");

  delete user1;
  delete user2;
  delete mediator;
}

/*
run result:
User2 recv msg: Hello
User1 recv msg: Hello
User2 recv msg: Hello
User2 recv msg: Hello
*/

例子三

#include <iostream>
#include <vector>
#include <string>

class Mediator;
class IUser;

struct commu_node{
  IUser *from;
  IUser *to;
};


class IMediator {
public:
  virtual void init(std::vector<IUser *> &user_vec,
      std::vector<commu_node> &node_vec) = 0;
  virtual void transmit(IUser *self, char *data, size_t size) = 0;
};

class IUser {
public:
  IUser(const std::string &name): name_(name) {}
  void send(char *data, size_t size) {
    mediator_->transmit(this, data, size);
  }
  virtual void set_mediator(IMediator *mediator) {
    mediator_ = mediator;
  }
  virtual void recv(char *data, size_t size) = 0;

  IMediator *mediator_ = nullptr;
  std::string name_;
};

class User1: public IUser {
public:
  User1(const std::string &name): IUser(name) {}
  virtual void recv(char *data, size_t size) {
    std::cout << name_ << " recv msg: " << data << std::endl;
  }
};
class User2: public IUser {
public:
  User2(const std::string &name): IUser(name) {}
  virtual void recv(char *data, size_t size) {
    std::cout << name_ << " recv msg: " << data << std::endl;
  }
};

class Mediator: public IMediator {
public:
  Mediator() { }

  virtual void init(std::vector<IUser *> &user_vec,
      std::vector<commu_node> &node_vec) {
    for (int i = 0; i < user_vec.size(); i++) {
      user_vec[i]->set_mediator(this);
    }
    // add check
    // ......

    node_vec_ = node_vec;
  }

  virtual void transmit(IUser *self, char *data, size_t size) {
    int i = 0;
    for (i = 0; i < node_vec_.size(); i++) {
      if (self == node_vec_[i].from) {
        std::cout << "[" << self->name_<< "]->[" << node_vec_[i].to->name_<< "]"
                  << " is: " << data << std::endl;
        node_vec_[i].to->recv(data, size);
        break;
      }
    }
    if (i == node_vec_.size()) {
      std::cout << "transmit failed: " << self->name_ << "->unknow" << std::endl;
    }
  }

  std::vector<commu_node> node_vec_;
};

int main() {
  IUser *user1 = new User1("user1");
  IUser *user2 = new User2("user2");

  std::vector<IUser *> user_vec{user1, user2};
  std::vector<commu_node> node_vec{{user1, user2}, {user2, user1}};

  IMediator *mediator = new Mediator();
  mediator->init(user_vec, node_vec);

  char data_tmp1[10] = "hello";
  char data_tmp2[10] = "I am fine";
  user1->send(data_tmp1, 10);
  std::cout << "-------------" << std::endl;
  user2->send(data_tmp2, 10);
  user1->send(data_tmp1, 10);
  user1->send(data_tmp1, 10);

  delete user1;
  delete user2;
  delete mediator;
}

/*
run result:
[user1]->[user2] is: hello
user2 recv msg: hello
-------------
[user2]->[user1] is: I am fine
user1 recv msg: I am fine
[user1]->[user2] is: hello
user2 recv msg: hello
[user1]->[user2] is: hello
user2 recv msg: hello
*/

例子四

#include <iostream>
#include <vector>
#include <string>

class Mediator;
class IUser;

struct commu_node{
  IUser *from_ = nullptr;
  IUser *to_ = nullptr;

  void to(IUser *to_tmp) {
    to_ = to_tmp;
  }
};

class IMediator {
public:
  virtual void init(std::vector<IUser *> &user_vec) = 0;
  virtual void transmit(IUser *self, char *data, size_t size) = 0;

  virtual commu_node *from(IUser *from_tmp) = 0;
};

class IUser {
public:
  IUser(const std::string &name): name_(name) {}
  void send(char *data, size_t size) {
    mediator_->transmit(this, data, size);
  }
  virtual void set_mediator(IMediator *mediator) {
    mediator_ = mediator;
  }
  virtual void recv(char *data, size_t size) = 0;

  IMediator *mediator_ = nullptr;
  std::string name_;
};

class User1: public IUser {
public:
  User1(const std::string &name): IUser(name) {}
  virtual void recv(char *data, size_t size) {
    std::cout << name_ << " recv msg: " << data << std::endl;
  }
};
class User2: public IUser {
public:
  User2(const std::string &name): IUser(name) {}
  virtual void recv(char *data, size_t size) {
    std::cout << name_ << " recv msg: " << data << std::endl;
  }
};

class Mediator: public IMediator {
public:
  Mediator() { }

  virtual void init(std::vector<IUser *> &user_vec) {
    for (int i = 0; i < user_vec.size(); i++) {
      user_vec[i]->set_mediator(this);
    }
  }

  virtual void transmit(IUser *self, char *data, size_t size) {
    int i = 0;
    for (i = 0; i < node_vec_.size(); i++) {
      if (self == node_vec_[i].from_) {
        std::cout << "[" << self->name_<< "]->[" << node_vec_[i].to_->name_<< "]"
                  << " is: " << data << std::endl;
        node_vec_[i].to_->recv(data, size);
        break;
      }
    }
    if (i == node_vec_.size()) {
      std::cout << "transmit failed: " << self->name_ << "->unknow" << std::endl;
    }
  }

  virtual commu_node *from(IUser *from_tmp) {
    commu_node node_tmp;
    node_tmp.from_ = from_tmp;
    node_vec_.push_back(node_tmp);
    return &node_vec_[node_vec_.size() - 1];
  }

  std::vector<commu_node> node_vec_;
};

int main() {
  IUser *user1 = new User1("user1");
  IUser *user2 = new User2("user2");

  std::vector<IUser *> user_vec{user1, user2};

  IMediator *mediator = new Mediator();
  mediator->init(user_vec);
  mediator->from(user1)->to(user2);
  mediator->from(user2)->to(user1);

  char data_tmp1[10] = "hello";
  char data_tmp2[10] = "I am fine";
  user1->send(data_tmp1, 10);
  std::cout << "-------------" << std::endl;
  user2->send(data_tmp2, 10);
  std::cout << "-------------" << std::endl;

  delete user1;
  delete user2;
  delete mediator;
}

/*
[user1]->[user2] is: hello
user2 recv msg: hello
-------------
[user2]->[user1] is: I am fine
user1 recv msg: I am fine
-------------
*/

例子五

#include <iostream>
#include <vector>
#include <string>

class Mediator;
class IUser;

struct commu_node{
  IUser *from_ = nullptr;
  IUser *to_ = nullptr;

  void to(IUser *to_tmp) {
    to_ = to_tmp;
  }
};

class IMediator {
public:
  virtual void init(std::vector<IUser *> &user_vec) = 0;
  virtual void get_send_list(IUser *self, std::vector<IUser *> &to_list) = 0;
  virtual void send_msg(std::vector<IUser *> &to_list, char *data, size_t size) = 0;

  virtual commu_node *from(IUser *from_tmp) = 0;
};

class IUser {
public:
  IUser(const std::string &name): name_(name) {}
  virtual void set_mediator(IMediator *mediator) {
    mediator_ = mediator;
  }
  virtual void send(char *data, size_t size) {
    std::vector<IUser *> to_list;
    mediator_->get_send_list(this, to_list);
    if (to_list.size() == 0) {
      return;
    }
    // debug
    std::cout << "[" << name_<< "] send <" << data << "> to:";
    for (int i = 0; i < to_list.size(); i++) {
      std::cout << " [" << to_list[i]->name_ << "]";
    }
    std::cout << std::endl;
    mediator_->send_msg(to_list, data, size);
  }
  virtual void recv(char *data, size_t size) = 0;

  IMediator *mediator_ = nullptr;
  std::string name_;
};

class User1: public IUser {
public:
  User1(const std::string &name): IUser(name) {}
  virtual void recv(char *data, size_t size) {
    // std::cout << name_ << " recv msg: " << data << std::endl;
    send(data, size);
  }
};
class User2: public IUser {
public:
  User2(const std::string &name): IUser(name) {}
  virtual void recv(char *data, size_t size) {
    // std::cout << name_ << " recv msg: " << data << std::endl;
    send(data, size);
  }
};

class Mediator: public IMediator {
public:
  Mediator() { }

  virtual void init(std::vector<IUser *> &user_vec) {
    for (int i = 0; i < user_vec.size(); i++) {
      user_vec[i]->set_mediator(this);
    }
  }

  virtual void get_send_list(IUser *self, std::vector<IUser *> &to_list) {
    for (int i = 0; i < node_vec_.size(); i++) {
      if (self == node_vec_[i].from_) {
        to_list.push_back(node_vec_[i].to_);
      }
    }
  }
  virtual void send_msg(std::vector<IUser *> &to_list, char *data, size_t size) {
    for (int i = 0; i < to_list.size(); i++) {
      to_list[i]->recv(data, size);
    }
  }

  virtual commu_node *from(IUser *from_tmp) {
    commu_node node_tmp;
    node_tmp.from_ = from_tmp;
    node_vec_.push_back(node_tmp);
    return &node_vec_[node_vec_.size() - 1];
  }

  std::vector<commu_node> node_vec_;
};

int main() {  
  IUser *user1 = new User1("user1");
  IUser *user2 = new User1("user2");
  IUser *user3 = new User1("user3");
  IUser *user4 = new User1("user4");
  IUser *user5 = new User1("user5");

  std::vector<IUser *> user_vec{user1, user2, user3, user4, user5};

  IMediator *mediator = new Mediator();
  mediator->init(user_vec);
  mediator->from(user1)->to(user2);
  // mediator->from(user1)->to(user2);
  mediator->from(user2)->to(user3);
  mediator->from(user3)->to(user4);
  mediator->from(user4)->to(user5);

  char data_tmp1[10] = "hello";
  user1->send(data_tmp1, 10);
  std::cout << "-------------" << std::endl;

  delete user1;
  delete user2;
  delete user3;
  delete user4;
  delete user5;
  delete mediator;
}
/*
./a.out
[user1] send <hello> to: [user2]
[user2] send <hello> to: [user3]
[user3] send <hello> to: [user4]
[user4] send <hello> to: [user5]
*/

例子六

#include <iostream>
#include <vector>
#include <string>
#include <memory>


class Mediator;
class IUser;

using spIuser = std::shared_ptr<IUser>;

class Message {
public:
  std::vector<char> vec_char;
};

struct commu_node{
  spIuser from_ = nullptr;
  spIuser to_ = nullptr;

  void to(spIuser to_tmp) {
    to_ = to_tmp;
  }
};

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

  // virtual void init(std::vector<spIuser> &user_vec) = 0;
  virtual void get_send_list(IUser *self, std::vector<spIuser> &to_list) = 0;
  virtual void send_msg(std::vector<spIuser> &to_list,
      std::shared_ptr<Message> msg) = 0;

  virtual std::shared_ptr<commu_node> &from(spIuser from_tmp) = 0;
};

class IUser {
public:
  IUser(const std::string &name): name_(name) {}
  virtual ~IUser() {}
  virtual void set_mediator(IMediator *mediator) {
    mediator_ = mediator;
  }
  virtual void send(std::shared_ptr<Message> msg) {
    std::vector<spIuser> to_list;
    mediator_->get_send_list(this, to_list);
    if (to_list.size() == 0) {
      return;
    }
    // debug
    std::cout << "[" << name_<< "] send <" << msg->vec_char[0] << "> to:";
    for (int i = 0; i < to_list.size(); i++) {
      std::cout << " [" << to_list[i]->name_ << "]";
    }
    std::cout << std::endl;
    mediator_->send_msg(to_list, msg);
  }
  virtual void recv(std::shared_ptr<Message> msg) = 0;

  IMediator *mediator_ = nullptr;
  std::string name_;
};

class User1: public IUser {
public:
  User1(const std::string &name): IUser(name) {}
  virtual ~User1() {}
  virtual void recv(std::shared_ptr<Message> msg) {
    send(msg);
  }
};
// class User2: public IUser {
// public:
//   User2(const std::string &name): IUser(name) {}
//   virtual void recv(std::shared_ptr<Message> msg) {
//     // std::cout << name_ << " recv msg: " << data << std::endl;
//     msg.vec_char[0] = 'A';
//     send(msg);
//   }
// };

class Mediator: public IMediator {
public:
  Mediator(std::vector<spIuser> &user_vec) {
    for (int i = 0; i < user_vec.size(); i++) {
      user_vec[i]->set_mediator(this);
    }
  }
  virtual ~Mediator() {}
  // virtual void init(std::vector<spIuser> &user_vec) {
  //   for (int i = 0; i < user_vec.size(); i++) {
  //     user_vec[i]->set_mediator(this);
  //   }
  // }

  virtual void get_send_list(IUser *self, std::vector<spIuser> &to_list) {
    for (int i = 0; i < node_vec_.size(); i++) {
      if (self == node_vec_[i]->from_.get()) {
        to_list.push_back(node_vec_[i]->to_);
      }
    }
  }
  virtual void send_msg(std::vector<spIuser> &to_list,
      std::shared_ptr<Message> msg) {
    for (int i = 0; i < to_list.size(); i++) {
      to_list[i]->recv(msg);
    }
  }

  virtual std::shared_ptr<commu_node> &from(spIuser from_tmp) {
    std::shared_ptr<commu_node> node_tmp = std::make_shared<commu_node>();
    node_tmp->from_ = from_tmp;
    node_vec_.push_back(node_tmp);
    return node_vec_[node_vec_.size() - 1];
  }

  std::vector<std::shared_ptr<commu_node>> node_vec_;
};

int main() {
  spIuser user1 = std::make_shared<User1>("user1");
  spIuser user2 = std::make_shared<User1>("user2");
  spIuser user3 = std::make_shared<User1>("user3");
  spIuser user4 = std::make_shared<User1>("user4");
  spIuser user5 = std::make_shared<User1>("user5");

  std::vector<spIuser> user_vec{user1, user2, user3, user4, user5};

  std::shared_ptr<IMediator> mediator = std::make_shared<Mediator>(user_vec);
  // mediator->init(user_vec);
  // mediator->from(user1)->to(user2);
  mediator->from(user1)->to(user2);
  mediator->from(user2)->to(user3);
  mediator->from(user3)->to(user4);
  mediator->from(user4)->to(user5);

  std::shared_ptr<Message> msg = std::make_shared<Message>();
  msg->vec_char.push_back('a');

  user1->send(msg);
  std::cout << "-------------" << std::endl;

  return 0;
}
/*
[user1] send <a> to: [user2]
[user2] send <a> to: [user3]
[user3] send <a> to: [user4]
[user4] send <a> to: [user5]
-------------
*/

上面的例子中,user1和user2两个模块通过中介者进行交互,user分别实现了send用来发送数据,recv来接受数据。它俩通过中介者进行通讯,在mediator类中,处理了两个模块的交互逻辑,在上面的例子中就是user1和user2之间互相发送接受消息。

优缺点(摘录于网络)

优点:

  • 单一职责原则。你可以将多个组件间的交流抽取到同一位置, 使其更易于理解和维护。
  • 开闭原则。 你无需修改实际组件就能增加新的中介者。
  • 你可以减轻应用中多个组件间的耦合情况。
  • 你可以更方便地复用各个组件。

缺点:

  • 当组件越来越多时,中介者类会变得很复杂,会处理很多逻辑。