使用中介者模式有哪些常见误区?
简化版
中介者模式常见误区包括:把中介者写成上帝类、简单调用也强行套中介者、同事对象仍然互相依赖、把事件总线等同于中介者、把业务能力全部塞进协调层。正确做法是让中介者只管理协作规则。
详细版
常见问题有:
- 中介者过胖:所有逻辑都往中介者里放;
- 过度设计:两个对象简单调用也加中介者;
- 假解耦:同事对象一边调用中介者,一边继续直接调用彼此;
- 边界不清:中介者不只协调,还负责校验、计算、持久化、通知等所有业务;
- 概念混淆:把观察者、事件总线、外观模式都直接说成中介者模式。
面试里要强调:中介者是协调中心,不是万能服务类。它应管理对象交互规则,而不是吞掉所有业务职责。
完整版教学
一、误区一:把中介者写成上帝类
这是最常见也最危险的问题。
一开始中介者只负责几个对象联动,后来需求不断增加:
- 校验逻辑放进来;
- 权限逻辑放进来;
- 数据库操作放进来;
- 日志和通知放进来;
- 异常补偿也放进来。
最后中介者变成一个几千行大类。
这种写法并没有降低复杂度,只是把复杂度集中到一个地方爆炸。
正确做法是:中介者负责协调,具体能力交给专门对象。
二、误区二:简单场景强行使用
如果只是两个对象之间的稳定调用:
orderService.createOrder();
payService.pay();
不一定需要中介者。
中介者适合的是多对象复杂交互,而不是所有方法调用。为了套模式而加中介者,会让代码多一层跳转,降低可读性。
三、误区三:同事对象仍然互相依赖
有些代码名义上用了中介者,但同事对象里仍然保存其他同事对象引用:
class A {
private Mediator mediator;
private B b;
}
这样中介者没有真正解耦。
如果 A 仍然直接调用 B,那么交互规则还是散落在对象之间。中介者只是多了一个入口,并没有发挥模式价值。
四、误区四:把事件总线直接等同于中介者
事件总线通常是发布订阅机制:
Publisher -> EventBus -> Subscribers
它主要负责事件分发,不一定知道具体业务协作规则。
中介者通常知道一组对象之间的关系,并主动协调它们。
所以更准确的说法是:事件总线可以体现中介者思想,但如果只是单纯发布订阅,它更接近观察者模式。
五、误区五:忽略中介者自身的拆分
当中介者变复杂时,不应该继续硬塞。
可以考虑:
- 按业务场景拆分多个中介者;
- 把校验、路由、权限、通知拆成独立策略或服务;
- 复杂流程使用状态机、责任链或工作流引擎;
- 异步跨服务协作用消息队列。
中介者模式是代码级对象协作工具,不是所有复杂流程的终点。
六、面试中怎么避免答偏
可以补充一句:
使用中介者模式时,最重要的是控制边界。它应该集中管理对象之间的协作规则,而不是变成包办所有业务逻辑的上帝类。
这句话能体现你不只是会背优点,也知道模式的代价。
七、常见误区与追问
中介者最危险的退化是把网状耦合变成单点复杂度。若1个 Mediator 有30个事件分支、注入20个同事并维护大量状态,修改任何流程都可能影响全局。应按业务场景拆分中介者,并让领域不变量留在同事或专门服务中。
| 检查维度 | 判定依据 |
|---|---|
| 合理中介者 | 协调有限场景,规则边界清楚 |
| 上帝中介者 | 分支膨胀、状态过多、所有变化集中 |
坏味道:event -> 30-way switch -> all components
心法:中介者负责交通规则,不负责替每辆车完成自己的业务。
- 误区:所有组件调用都要经过中介者。 组件内部能力和无关协作无需强行集中。
- 追问:如何拆分过大的中介者? 按用例、页面区域或业务子域拆分,并提取共享服务。
- 误区:中介者天然解决循环事件。 A 触发 B、B 再触发 A 仍可能死循环,需要来源或状态保护。
- 追问:事件字符串有什么风险? 拼写错误无法编译期发现,优先使用类型化事件或明确方法。
- 追问:异步中介者要补什么能力? 需要顺序、重试、幂等、失败观测和背压策略。
八、加强记忆
中介者模式最怕两个极端:不用时对象互相缠绕,乱用时中介者变成上帝类。正确姿势是让同事对象保持简单,把对象之间的协作规则放到中介者,同时把校验、计算、存储等独立能力拆出去。