相似模式区分
📅 2026/7/7 7:01:08
👁️ 阅读次数
📝 编程学习
总览
| 模式 | 核心意图 | 典型场景 |
|---|---|---|
| 中介者 | 协调多个对象间的复杂交互 | 智能家居中控、聊天室、GUI组件联动 |
| 观察者 | 一对多的通知机制 | 事件监听、消息订阅、数据绑定 |
| 门面 | 为子系统提供统一入口 | API封装、SDK入口、简化调用 |
中介者 vs 观察者
| 维度 | 中介者模式 | 观察者模式 |
|---|---|---|
| 核心意图 | 集中协调多对象间的双向交互 | 一对多的单向通知 |
| 结构差异 | 中介者知道所有同事,同事只知道中介者 | 主题知道所有观察者,观察者只知道主题 |
| 关注点 | 对象间的交互规则和联动逻辑 | 状态变化的通知分发 |
| 典型场景 | 智能家居中控、聊天室、工作流引擎 | 事件监听、消息订阅、数据绑定 |
逐步区分法:
- 如果对象间需要双向交互(A变化影响B,B变化可能再影响A)→ 选中介者
- 如果只是单向通知(主题变化通知观察者,观察者不反向影响主题)→ 选观察者
- 如果联动规则复杂需要集中管理 → 选中介者
简单记忆口诀:中介者管双向协调,观察者管单向通知。
推荐:大多数场景下,复杂联动用中介者,简单通知用观察者。Spring事件机制是观察者的变体,但可以用于简单联动场景。
中介者 vs 门面
| 维度 | 中介者模式 | 门面模式 |
|---|---|---|
| 核心意图 | 协调多对象间的交互,降低耦合 | 为复杂子系统提供统一入口,简化调用 |
| 结构差异 | 中介者参与业务逻辑,协调对象间的交互 | 门面只是封装调用入口,不参与子系统内部逻辑 |
| 关注点 | 对象间的交互规则 | 子系统的使用接口 |
| 典型场景 | 聊天室、GUI组件联动、工作流引擎 | API封装、SDK入口、简化配置 |
逐步区分法:
- 如果需要协调多个对象间的交互(对象间有联动)→ 选中介者
- 如果只是简化调用入口(提供一个统一接口调用多个子系统)→ 选门面
- 如果对象需要反向通知中介者 → 选中介者(门面是单向的)
简单记忆口诀:中介者管交互,门面管入口。
推荐:门面用于简化外部调用,中介者用于协调内部交互。两者可以组合使用:门面作为外部入口,中介者协调内部逻辑。
练习题目
智能家居中控系统
题目描述:小明正在设计一个智能家居系统,系统中有灯(Light)、窗帘(Curtain)、空调(AC)三种设备,它们通过智能家居中控(中介者)来协调联动。设备之间不直接通信,所有联动逻辑由中控负责。
中控的联动规则:
- 空调开启 → 自动关闭窗帘(避免冷气流失)
- 空调关闭 → 自动打开窗帘
- 窗帘关闭 → 自动开灯(补充采光)
- 窗帘打开 → 自动关灯(自然光足够)
注意:联动可能产生连锁反应。例如开启空调 → 关闭窗帘 → 开灯。同一设备在同一次连锁中状态只改变一次,避免循环触发。
输入描述:第一行包含三个字符串,分别是灯、窗帘、空调的名称,用空格分隔。第二行包含三个字符串,分别是灯、窗帘、空调的初始状态(on 或 off),用空格分隔。接下来每行包含一个操作,格式为设备名 操作(操作为 on 或 off),直到输入结束。
输出描述:对于每个操作,按联动触发顺序输出每个状态发生变化的设备,格式为设备名 on 或设备名 off。若操作未导致状态变化(设备已在目标状态),则不输出。
输入示例:
Light Curtain AC off on off AC on AC off Curtain off输出示例:
AC on Curtain off Light on AC off Curtain on Light off Curtain off Light on解题思路:本题的核心是中介者模式的连锁反应机制。
角色对应:
- Mediator(抽象中介者):
Mediator接口,定义send方法 - ConcreteMediator(具体中介者):
SmartHomeMediator,实现联动规则(空调→窗帘→灯) - Colleague(抽象同事类):
Device抽象类,持有中介者引用,提供send和receive方法 - ConcreteColleague(具体同事类):
Light、Curtain、AC,具体设备实现
连锁反应机制:
- 用户操作设备(如开启空调)→ 调用
device.send("on") send方法更新状态并输出,然后通知中介者mediator.send("on", this)- 中介者根据联动规则,调用相关设备的
receive方法(如关闭窗帘) receive方法更新状态并输出,再次通知中介者,形成递归连锁- 避免循环触发:在
send和receive中检查if (!status.equals(message)),如果状态已经是目标状态则不处理
import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String line = sc.nextLine(); String[] names = line.split(" "); line = sc.nextLine(); String[] status = line.split(" "); Mediator mediator = new SmartHomeMediator(); Light light = new Light(mediator, names[0], status[0]); Curtain curtain = new Curtain(mediator, names[1], status[1]); AC ac = new AC(mediator, names[2], status[2]); mediator.setLight(light); mediator.setCurtain(curtain); mediator.setAc(ac); Map<String, Device> map = new HashMap<>(); map.put(names[0], light); map.put(names[1], curtain); map.put(names[2], ac); while (sc.hasNext()) { String name = sc.next(); String s = sc.next(); Device d = map.get(name); d.send(s); } } } // 抽象中介者 interface Mediator { public void send(String message, Device device); } // 具体中介者:智能家居中控 class SmartHomeMediator implements Mediator { private Light light; private Curtain curtain; private AC ac; public void setLight(Light light) { this.light = light; } public void setCurtain(Curtain curtain) { this.curtain = curtain; } public void setAc(AC ac) { this.ac = ac; } public void send(String message, Device device) { // 空调状态变化触发窗帘联动 if (device instanceof AC) { if (message.equals("on")) { curtain.receive("off"); // 规则1:空调开 → 关窗帘 } else { curtain.receive("on"); // 规则2:空调关 → 开窗帘 } } // 窗帘状态变化触发灯联动 else if (device instanceof Curtain) { if (message.equals("on")) { light.receive("off"); // 规则4:窗帘开 → 关灯 } else { light.receive("on"); // 规则3:窗帘关 → 开灯 } } // 灯状态变化不触发联动 } } // 抽象同事类:设备基类 abstract class Device { protected Mediator mediator; protected String name; protected String status; public Device(Mediator mediator, String name, String status) { this.mediator = mediator; this.name = name; this.status = status; } public String getName() { return name; } public String getStatus() { return status; } // 用户操作触发状态变化 public void send(String message) { if (!status.equals(message)) { System.out.println(name + " " + message); status = message; mediator.send(message, this); // 通知中介者 } } // 中介者通知触发状态变化 public void receive(String message) { if (!status.equals(message)) { System.out.println(name + " " + message); status = message; mediator.send(message, this); // 状态变化后通知中介者,形成连锁 } } } // 具体同事类:灯 class Light extends Device { public Light(Mediator mediator, String name, String status) { super(mediator, name, status); } } // 具体同事类:窗帘 class Curtain extends Device { public Curtain(Mediator mediator, String name, String status) { super(mediator, name, status); } } // 具体同事类:空调 class AC extends Device { public AC(Mediator mediator, String name, String status) { super(mediator, name, status); } }
编程学习
技术分享
实战经验