设计模式---中介者模式
定义与设计思路
-
定义:用一个中介对象来封装一系列对象交互。中介者使各对象不需要相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式又称为调停者模式,属于行为型模式。
-
设计思路:用一个中介对象来封装一系列的对象交互操作,中介者模式使得对象之间不需要显示的相互引用,从而使得系统或模块内部相互解耦,而且可以独立的改变它们至今的交互
中介者模式的引入:机场控制塔
想象一个繁忙的机场,有许多飞机在同一时间内起飞和降落。如果每架飞机都直接与其他飞机通信,协商谁该先起飞、谁该先降落,整个机场的调度将变得非常复杂。每架飞机都要知道其他所有飞机的状态、飞行路线、优先级等,导致信息的传递和处理变得混乱而低效。
问题:飞机之间的复杂通信
直接通信导致混乱: 每架飞机要知道并与其他所有飞机通信,管理起飞、降落的顺序会变得非常困难且危险。
- 维护成本高: 增加或移除一架飞机,所有飞机的通信方式都需要更新,增加了维护的难度。
- 耦合度过高: 每架飞机相互依赖,任何一个飞机的变动可能会影响整个系统的稳定性。
中介模式解决问题:引入机场控制塔
为了简化调度过程,机场引入了控制塔作为中介者。控制塔的职责是协调所有飞机的起飞和降落,保证每架飞机都能安全有- 序地运行。这样,每架飞机只需要与控制塔通信,而不需要关心其他飞机的具体状态。
- 控制塔(中介者): 控制飞机的起飞和降落顺序,管理它们的路线和时间安排。
- 飞机(同事类): 负责向控制塔报告自己的状态(如准备起飞、准备降落等),并接收控制塔的指令(如可以起飞或等待)。
中介模式的作用:
去耦合: 飞机之间不再直接通信,只需要和控制塔交互,这大大简化了飞机之间的相互依赖。
集中控制: 所有的调度逻辑都集中在控制塔中,便于统一管理,维护起来更加简单。
易于扩展: 新的飞机可以轻松加入机场系统,只需要和控制塔通信,而不需要重新调整其他飞机的通信逻辑。
中介者模式的设计框架
需要一个中介者类和同事类,目的是通过中介者类对象对象完成同事类实例之间的信息交互。其中,中介者类中需要有一个储存注册进来的同事对象的列表、发送消息的接口(协助同事实例完成消息的转发)、注册函数(完成同事实例的注册)。所有的同事类实例包含一个发布消息接口、接收消息的接口(接收中介转发的消息),另外包含一个中介实例成员变量(用于完成消息的转发的接口对象)。
中介模式的关键要素:
- 中介者(Mediator): 中介者负责定义对象之间的通信接口,具体的通信逻辑则由具体的中介者实现。
- 具体中介者(Concrete Mediator): 这是中介者的具体实现,它维护所有参与者对象,并处理这些对象之间的通信。
- 同事类(Colleague): 这些是参与通信的对象,它们通过中介者进行相互通信,而不是直接引用其他同事对象。
cpp
#include <bits/stdc++.h>
//
//中介者模式
//关键代码:对象 Colleague 之间的通信封装到一个类中单独处理
//
class Mediator;
//抽象人(同事类)
class Person
{
protected:
std::shared_ptr<Mediator> m_mediator; //中介类实例
public:
Person(const std::shared_ptr<Mediator> pMediator) : m_mediator(pMediator) {}
//虚析构函数
virtual ~Person() = default;
//向中介发送信息
virtual void SendMessage(const std::string &message) = 0;
//从中介获取信息
//message 中介向该对象发送的信息/从中介获取的信息
virtual void GetMessage(const std::string &message) = 0;
};
//抽象中介机构
class Mediator
{
public:
virtual ~Mediator() = default;
//由于后面this指针的原因,此处未采用智能指针
virtual void Send(std::string message, const Person *from_person) const = 0;
virtual void Register(std::shared_ptr<Person> pPerson) = 0;
};
//租房者A
class RenterA : public Person
{
public:
RenterA(const std::shared_ptr<Mediator> mediator) : Person(mediator) {}
void SendMessage(const std::string &message) override
{
m_mediator->Send(message, this);
}
void GetMessage(const std::string &message) override
{
std::cout << "租房者A收到信息" << message << std::endl;;
}
};
//租房者B
class RenterB : public Person
{
public:
RenterB(const std::shared_ptr<Mediator> mediator) : Person(mediator) {}
void SendMessage(const std::string &message) override
{
m_mediator->Send(message, this);
}
void GetMessage(const std::string &message) override
{
std::cout << "租房者B收到信息" << message << std::endl;;
}
};
//房东
class Landlord : public Person
{
public:
Landlord(const std::shared_ptr<Mediator> mediator) : Person(mediator) {}
void SendMessage(const std::string &message) override
{
m_mediator->Send(message, this);
}
void GetMessage(const std::string &message) override
{
std::cout << "房东收到信息:" << message << std::endl;;
}
};
//房屋中介
class HouseMediator : public Mediator
{
private:
//也可以采用多个list,将多个房东放入一个list,将多个求租者放入一个list
std::vector<std::shared_ptr<Person>> m_pPersonList;
public:
void Register(const std::shared_ptr<Person> pPerson) override
{
//没有添加该同事,则添加进去
auto iter = m_pPersonList.begin();
for (; iter != m_pPersonList.end(); ++iter)
{
if (*iter == pPerson)
break;
}
if (iter == m_pPersonList.end())
m_pPersonList.emplace_back(pPerson);
}
void Send(std::string message, const Person *from_person) const override
{
//接收消息的对象为该对象的对应对象
for (const auto item:m_pPersonList)
{
//此处采用typeid,而非直接判断指针是否相等为同一个对象.
if (typeid(*item.get()) != typeid(*from_person))
{
item->GetMessage(message);
}
}
}
};
int main() {
std::shared_ptr<Mediator> pHouseMediator = std::make_shared<HouseMediator>();
std::shared_ptr<Person> pRenterA = std::make_shared<RenterA>(pHouseMediator);
std::shared_ptr<Person> pRenterB = std::make_shared<RenterB>(pHouseMediator);
std::shared_ptr<Person> pLandlord = std::make_shared<Landlord>(pHouseMediator);
pHouseMediator->Register(pRenterA);
pHouseMediator->Register(pRenterB);
pHouseMediator->Register(pLandlord);
pLandlord->SendMessage("出租房子:中山路100号,50平米,2000元一个月");//所有的求租者将会收到该消息
std::cout << std::string(50, '-') << std::endl;
pRenterA->SendMessage("我想在中山路附近租套房子,价格1500元一个月");//所有的房东将会收到该消息
return 0;
}
输出
cpp
租房者A收到信息出租房子:中山路100号,50平米,2000元一个月
租房者B收到信息出租房子:中山路100号,50平米,2000元一个月
--------------------------------------------------
租房者B收到信息我想在中山路附近租套房子,价格1500元一个月
房东收到信息:我想在中山路附近租套房子,价格1500元一个月
发送的消息通过中介转发给租房者,租房者发送的消息通过中介转发给
感谢大佬的讲解
https://blog.csdn.net/leonardohaig/article/details/109963550