概述
中介者模式是一种强大且灵活的设计模式,适用于需要优化对象间通信的场景。中介者模式通过引入一个中介对象,来封装一系列对象之间的交互。在没有中介者的情况下,这些对象之间可能会直接相互引用,导致系统中的类紧密耦合,难以维护和扩展。而通过使用中介者模式,可以将对象间的通信集中到一个中介者对象中,从而减少了对象之间的直接依赖,提高了系统的灵活性和可维护性。
空中交通管制是现实生活中运用中介者模式的一个典型例子。在航空业中,空中交通管制系统扮演着中介者的角色。每架飞机就像是同事类,它们需要与其他飞机进行通信,以确保飞行的安全和效率。然而,如果让每架飞机都直接与其它所有飞机进行通信,不仅复杂度极高,而且容易引发混乱甚至危险。因此,空中交通管制员作为中介者,负责协调所有飞机的起飞、降落以及飞行路径,确保它们之间不会发生碰撞。在这个过程中,飞机只需遵循空中交通管制员的指示,而不需要知道其他飞机的具体情况。
基本原理
中介者模式的核心思想是:通过引入一个中介对象,来封装一系列对象之间的交互,从而减少这些对象之间的直接依赖。在没有中介者的情况下,对象之间可能会形成复杂的网状结构,导致系统难以维护和扩展。中介者模式使得每个对象只需与中介者进行通信,而不需要知道其他对象的存在或操作方式,这大大降低了系统的耦合度,并提高了灵活性和可维护性。
中介者模式主要由以下三个核心组件构成。
1、抽象中介者。定义了同事类与中介者之间通信的接口,通常是一个接口或抽象类,具体实现留给子类完成。目的是为具体的中介者提供一个统一的接口,以便于同事类与中介者之间的交互。
2、具体中介者。实现了抽象中介者的接口,包含了对同事类的引用,并负责处理同事类之间的交互逻辑。具体中介者了解所有同事类,并能够根据需要调用同事类的方法,或者通知其他同事类发生了某些事件。
3、同事类。每个同事类都知道自己应该与中介者进行通信,但不知道也不关心其他同事类的存在或操作。同事类通常会持有对中介者的引用,并通过中介者发送消息给其他同事类。同事类只负责自身的业务逻辑,而不直接与其他同事类交互,所有的交互都通过中介者来进行。
基于上面的核心组件,中介者模式的实现主要有以下四个步骤。
1、定义抽象中介者。创建一个接口或抽象类,定义同事类与中介者之间通信的方法。这些方法通常是用于发送消息,或通知其他同事类发生的变化。
2、创建具体中介者。实现抽象中介者接口,创建具体的中介者类。在具体中介者中,管理所有同事类的引用,并实现同事类之间交互的具体逻辑。确保具体中介者能够接收来自一个同事类的消息,并将消息转发给相关的同事类。
3、定义同事类。创建同事类,它持有一个指向中介者的引用。同事类通过中介者发送消息给其他同事类,而不是直接与它们通信。同事类还应包含一些基本的行为和状态,以及处理接收到的消息的方法。
4、集成同事类与中介者。将同事类注册到中介者中,使得中介者可以管理这些同事类。当同事类需要与其他同事类通信时,它通过中介者发送消息,而不是直接调用其他同事类的方法。
实战代码
在下面的实战代码中,我们使用中介者模式模拟了空中交通管制的实现。
首先,我们定义了抽象中介者接口CAirTrafficControl。它声明了注册飞机和更新位置的方法,为具体中介者提供了统一的操作接口。
接着,通过CConcreteAirTrafficControl实现了这些方法,并添加了检查潜在碰撞的功能。在该类中,使用一个哈希表m_mapAircraft来存储所有已注册飞机的引用,另一个哈希表m_mapPosition记录每架飞机的位置坐标。每当有飞机更新其位置时,就会调用UpdatePosition方法。该方法不仅更新了飞机的位置信息,还会触发CheckForCollisions函数,以检查是否有任何两架飞机的距离小于预设的安全距离SAFE_DISTANCE。如果检测到可能的碰撞,AvoidCollision方法将被调用,通知相关飞机采取避让措施。
然后,我们定义了同事类CAircraft。它代表系统中的各个飞机,并持有一个指向中介者的引用,可以通过中介者报告自己的当前位置。每个飞机实例都知道如何向空中交通控制中心报告其最新位置,并且当接收到碰撞警告时,会打印出相应的避让信息。
最后,在main函数中,我们创建了一个具体的空中交通控制中心实例,并注册了两架飞机。通过调用UpdatePosition方法更新这两架飞机的位置,模拟它们的移动过程。随着飞机2逐渐靠近飞机1,最终触发了碰撞检测机制,导致两架飞机都收到了避让指令,以避免潜在的碰撞。
#include <iostream>
#include <unordered_map>
#include <string>
#include <cmath>
using namespace std;
class CAircraft;
// 抽象中介者
class CAirTrafficControl
{
public:
virtual void RegisterAircraft(const string& id, CAircraft* aircraft) = 0;
virtual void UpdatePosition(const string& senderId, double x, double y) = 0;
};
// 具体中介者:空中交通控制中心
class CConcreteAirTrafficControl : public CAirTrafficControl
{
public:
void RegisterAircraft(const string& id, CAircraft* aircraft) override
{
m_mapAircraft[id] = aircraft;
}
void UpdatePosition(const string& senderId, double x, double y) override
{
m_mapPosition[senderId] = {x, y};
CheckForCollisions(senderId);
}
void CheckForCollisions(const string &senderId);
private:
bool IsTooClose(double x1, double y1, double x2, double y2)
{
return sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2)) < SAFE_DISTANCE;
}
private:
struct Position
{
double x;
double y;
};
unordered_map<string, CAircraft*> m_mapAircraft;
unordered_map<string, Position> m_mapPosition;
// 安全距离
const double SAFE_DISTANCE = 10.0;
};
// 同事类:飞机
class CAircraft
{
public:
CAircraft(const string& id, CAirTrafficControl* atc) : m_id(id), m_pAtc(atc) {}
string GetId() const { return m_id; }
void UpdatePosition(double x, double y)
{
cout << m_id << " updates pos to (" << x << ", " << y << ")" << endl;
m_pAtc->UpdatePosition(m_id, x, y);
}
void AvoidCollision(const string& otherId)
{
cout << GetId() << " taking action to avoid collision with " << otherId << endl;
}
private:
string m_id;
CAirTrafficControl* m_pAtc;
};
void CConcreteAirTrafficControl::CheckForCollisions(const string& senderId)
{
auto itSender = m_mapPosition.find(senderId);
if (itSender == m_mapPosition.end())
{
return;
}
for (auto& it : m_mapPosition)
{
if (it.first != senderId &&
IsTooClose(itSender->second.x, itSender->second.y, it.second.x, it.second.y))
{
cout << "Potential collision between " << senderId << " and " <<
it.first << endl;
m_mapAircraft[it.first]->AvoidCollision(senderId);
m_mapAircraft[senderId]->AvoidCollision(it.first);
}
}
}
int main()
{
CConcreteAirTrafficControl atc;
CAircraft aircraft1("Flight 101", &atc);
CAircraft aircraft2("Flight 202", &atc);
atc.RegisterAircraft(aircraft1.GetId(), &aircraft1);
atc.RegisterAircraft(aircraft2.GetId(), &aircraft2);
// 飞机1更新位置
aircraft1.UpdatePosition(100, 100);
// 飞机2更新位置,接近飞机1
aircraft2.UpdatePosition(150, 150);
// 飞机2进一步靠近飞机1,触发碰撞警告
aircraft2.UpdatePosition(105, 105);
return 0;
}
总结
在复杂的系统中,组件间的通信往往变得异常复杂。中介者模式提供了一种集中管理这些通信的方式,使得组件间的交互逻辑更加简洁明了。由于同事类之间的交互被集中在中介者中,因此当需要添加新的同事类或修改现有的交互逻辑时,只需要调整中介者的实现即可,而不会影响到其他同事类。这大大提高了系统的灵活性和可维护性,有助于快速响应需求变化。
但如果系统中有大量同事类频繁地与中介者进行交互,那么中介者可能会成为性能瓶颈。特别是在高并发环境下,中介者的处理能力直接影响到整个系统的吞吐量和响应速度。因此,在设计中介者时,需要特别注意其性能表现,避免出现单点故障。