Mediator模式通过星型结构解耦对象交互,避免继承的硬编码和观察者模式的隐式依赖;需防止其沦为上帝对象,应仅封装协调规则、使用弱引用或智能指针管理生命周期,并借助模板实现类型安全注册与调用。

为什么不用继承或观察者来替代 Mediator
继承会把通信逻辑硬编码进类层次,一旦新增交互角色就得改基类;观察者模式适合一对多通知,但多个对象需要互相协调时(比如 A 提交后 B 校验、C 刷新界面),事件流容易失控,监听器之间又产生隐式依赖。Mediator 把这种网状调用收束成星型结构,所有交互都走 Mediator 实例,角色类只认中介者,不认彼此。
如何避免 Mediator 变成上帝对象
常见错误是把所有业务逻辑塞进 Mediator,导致它既处理 UI 事件、又做数据校验、还管网络请求。正确做法是只封装「协调规则」:谁在什么条件下通知谁,不碰具体实现。例如:
-
Mediator::onSubmit()调用validator->validate()和ui->refresh(),但不写校验逻辑本身 - 每个同事类(
Colleague子类)只暴露窄接口,如enableSubmit(bool)、showError(const std::string&) - Mediator 持有各同事的弱引用(
std::weak_ptr)或裸指针,避免循环引用
用模板简化同事类注册与类型安全调用
手写 setValidator(Validator*)、setUI(UI*) 容易漏设、空指针崩溃。用模板 + 类型擦除可自动绑定:
template<typename T>
void registerColleague(std::shared_ptr<T> ptr) {
colleagues_[typeid(T).name()] = std::static_pointer_cast<Colleague>(ptr);
ptr->setMediator(this);
}
调用时直接 get<Validator>()->validate(),编译期检查类型,运行时避免 dynamic_cast 开销。注意 type_info::name() 在不同编译器下可能不稳定,生产环境建议用枚举或字符串字面量作 key。
立即学习“C++免费学习笔记(深入)”;
析构顺序引发的 crash 怎么防
典型场景:UI 对象先析构,Mediator 还在尝试调用它的 updateStatus()。解决关键不是加判空(治标),而是控制生命周期:
- 让 Mediator 持有所有同事的
std::shared_ptr,同事持std::weak_ptr<Mediator>—— 确保 Mediator 活得最久 - 或更轻量:同事在析构函数里显式调用
mediator_->removeColleague(this),Mediator 内部用std::vector<Colleague*>存裸指针并及时清理 - 禁止在 Mediator 析构函数中触发任何同事方法调用(包括信号、回调)
真正难处理的是跨线程场景:一个线程正在调用 mediator->notify(),另一个线程刚 delete 了某个同事。这时候裸指针方案必须配合锁或 hazard pointer,shared_ptr 方案则天然线程安全(但注意 shared_ptr 的控制块是线程安全的,所指对象不是)。


















