把网状交互收成星形
当很多对象需要互相通信时,两两引用会形成数量巨大的依赖:改动一个对象的分支,就要检查所有对手方。中介者模式引入一个中央协调者,同事对象只与中介者通信,交互规则集中在一处,依赖关系从网状变成星形。
基本信息
| 意图 | 把多对多的互相引用收敛为星形结构 |
|---|---|
| 应用 | 界面控件联动、对话框编排、消息路由 |
| 近亲 | 事件总线是它的常见演进形态,由中心分发者路由消息 |
| 风险 | 中介者膨胀成上帝对象 |
典型使用场景
- 表单联动:某个字段变化后,其他字段的启用状态与默认值随之改变
- 对话框编排:确定与取消按钮、各输入框的校验状态互相制约
- 调度场景:航班与跑道不直接交互,由塔台统一分配
- 服务端消息路由:用户之间不直接互连,消息经房间或服务端转发
- 流程编排:由编排器统一调度多个参与者,参与者之间不直接互相调用
形态示意
形态示意
# 之前:A 与 B、C 两两互知,依赖成网状,改一处要检查所有对手方
# 之后:A -> Mediator -> B/C,依赖线性化
class DialogMediator:
def input_changed(self, src): # 统一入口:谁变化了
if src is self.name_field:
self.save_button.enabled = bool(self.name_field.text)
self.hint_label.text = '请填写姓名' if not src.text else ''收益与代价对照
| 方面 | 收敛前 | 收敛后 |
|---|---|---|
| 依赖关系 | 参与者之间两两互相引用 | 每个参与者只指向中介者 |
| 改交互规则 | 要改多处参与者 | 只改中介者一处 |
| 参与者复用 | 耦合于具体对手方 | 只依赖中介接口 |
| 主要风险 | 关系散乱难追踪 | 中介者膨胀成上帝对象 |
中介者与观察者的分工不同:观察者解决一对多通知,订阅者互不相识;中介者解决多对多交互规则,规则由中介者掌握。实际实现常把两者叠加,中介者内部用订阅收集变更事件。
中介者最容易变成上帝对象。可按场景给方法分类(校验类、可见性类、导航类),其中一类超过一定规模就拆成独立的协作对象,让中介者只保留转发与顺序。