相似模式区分

📅 2026/7/7 7:01:08 👁️ 阅读次数 📝 编程学习
相似模式区分

总览

模式核心意图典型场景
中介者协调多个对象间的复杂交互智能家居中控、聊天室、GUI组件联动
观察者一对多的通知机制事件监听、消息订阅、数据绑定
门面为子系统提供统一入口API封装、SDK入口、简化调用

中介者 vs 观察者

维度中介者模式观察者模式
核心意图集中协调多对象间的双向交互一对多的单向通知
结构差异中介者知道所有同事,同事只知道中介者主题知道所有观察者,观察者只知道主题
关注点对象间的交互规则和联动逻辑状态变化的通知分发
典型场景智能家居中控、聊天室、工作流引擎事件监听、消息订阅、数据绑定

逐步区分法

  1. 如果对象间需要双向交互(A变化影响B,B变化可能再影响A)→ 选中介者
  2. 如果只是单向通知(主题变化通知观察者,观察者不反向影响主题)→ 选观察者
  3. 如果联动规则复杂需要集中管理 → 选中介者

简单记忆口诀:中介者管双向协调,观察者管单向通知。

推荐:大多数场景下,复杂联动用中介者,简单通知用观察者。Spring事件机制是观察者的变体,但可以用于简单联动场景。

中介者 vs 门面

维度中介者模式门面模式
核心意图协调多对象间的交互,降低耦合为复杂子系统提供统一入口,简化调用
结构差异中介者参与业务逻辑,协调对象间的交互门面只是封装调用入口,不参与子系统内部逻辑
关注点对象间的交互规则子系统的使用接口
典型场景聊天室、GUI组件联动、工作流引擎API封装、SDK入口、简化配置

逐步区分法

  1. 如果需要协调多个对象间的交互(对象间有联动)→ 选中介者
  2. 如果只是简化调用入口(提供一个统一接口调用多个子系统)→ 选门面
  3. 如果对象需要反向通知中介者 → 选中介者(门面是单向的)

简单记忆口诀:中介者管交互,门面管入口。

推荐:门面用于简化外部调用,中介者用于协调内部交互。两者可以组合使用:门面作为外部入口,中介者协调内部逻辑。

练习题目

智能家居中控系统

题目描述:小明正在设计一个智能家居系统,系统中有灯(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抽象类,持有中介者引用,提供sendreceive方法
  • ConcreteColleague(具体同事类)LightCurtainAC,具体设备实现

连锁反应机制

  1. 用户操作设备(如开启空调)→ 调用device.send("on")
  2. send方法更新状态并输出,然后通知中介者mediator.send("on", this)
  3. 中介者根据联动规则,调用相关设备的receive方法(如关闭窗帘)
  4. receive方法更新状态并输出,再次通知中介者,形成递归连锁
  5. 避免循环触发:在sendreceive中检查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); } }