在智能家居系统中我们可以将四种经典设计模式——观察者模式Observer、策略模式Strategy、命令模式Command和单例模式Singleton——有机串联形成一个真实、协同工作的场景体现“模式即解决方案”的工程思维。 场景设定智能客厅控制系统用户通过手机App或语音助手控制客厅设备灯光、空调、窗帘、音响系统需支持实时状态同步如灯光变亮时App界面自动更新多种预设场景如“观影模式”“会客模式”“睡眠模式”每种模式下设备行为不同可撤销/重做操作如误关灯后一键恢复全局唯一中央控制器避免多实例导致状态冲突✅ 四种模式的场景化落地观察者模式Observer→ 设备状态实时同步Light、AC、Curtain等设备作为被观察者Subject手机App界面、语音播报模块、日志服务作为观察者Observer当用户调用light.turnOn()设备内部触发notifyObservers()所有观察者自动刷新UI、播报“灯光已开启”、记录日志。→ 解耦设备逻辑与展示/通知逻辑支持动态增删监控端。策略模式Strategy→ 场景化行为切换定义统一接口SceneStrategy含execute()方法实现具体策略类MovieModeStrategy关灯降帘开音响调低空调、GuestModeStrategy开主灯调高空调播放轻音乐、SleepModeStrategy渐暗灯关窗帘静音音响设26℃中央控制器持有一个currentStrategy: SceneStrategy用户选择场景时仅需setStrategy(new MovieModeStrategy())再调用execute()即可批量调度设备。→ 避免大量 if-else新增场景无需修改控制器符合开闭原则。命令模式Command→ 可撤销/队列化操作每个操作封装为命令对象TurnOnLightCommand、CloseCurtainCommand、UndoableCommand接口含execute()/undo()控制器维护CommandHistory栈如StackCommand每次执行前push(command)用户点击“撤销”弹出栈顶命令并调用其undo()如恢复灯的上一亮度值支持宏命令MacroCommand组合多个命令实现“一键观影”原子操作。→ 将请求参数化支持事务、日志、延时执行如定时开关。单例模式Singleton→ 全局中央控制器SmartHomeController采用线程安全单例双重检查锁 volatile所有设备、策略、命令均通过SmartHomeController.getInstance()获取唯一入口保证设备状态、策略上下文、命令历史全局一致防止多实例导致空调被两个控制器反复启停。→ 是整个系统的“大脑中枢”天然适配IoT设备资源受限、强一致性需求。 四者协同流程示例启动“观影模式”用户在App点击【观影模式】 → App调用controller.setStrategy(new MovieModeStrategy())controller.executeCurrentStrategy()→ 策略内部逐个创建并执行命令new TurnOffLightCommand().execute()、new CloseCurtainCommand().execute()…每个命令执行时对应设备状态变更 → 触发观察者通知 → App UI实时变灰、音响图标亮起所有命令入栈 → 用户点“撤销”依次undo()恢复全程只存在一个controller实例确保策略、命令、观察者注册均在同一上下文中。✅ 这不是模式堆砌而是以问题驱动状态同步用观察者行为变化用策略操作管理用命令全局协调用单例——每个模式解决一个明确痛点且彼此协作无耦合。# 简化示意单例控制器 策略 命令 观察者联动classSmartHomeController:_instanceNone_observers[]def__new__(cls):ifcls._instanceisNone:cls._instancesuper().__new__(cls)cls._instance.strategyNonecls._instance.history[]returncls._instancedefset_strategy(self,strategy):self.strategystrategydefexecute_current_strategy(self):ifself.strategy:commandsself.strategy.get_commands()# 返回[Command]forcmdincommands:cmd.execute()self.history.append(cmd)# 设备执行后自动 notify_observers()defadd_observer(self,obs):self._observers.append(obs)defnotify_observers(self):[obs.update()forobsinself._observers]这是一个典型的事件驱动、跨上下文协调问题。在现有四模式观察者、策略、命令、单例基础上最自然且低侵入的扩展是引入责任链模式Chain of Responsibility——但它需与观察者模式深度协同并辅以命令模式的增强封装形成“事件触发 → 条件分发 → 跨域执行”的闭环。✅ 为什么不是新增策略或单例策略模式聚焦“同一场景内行为变体”不解决“从A房间事件触发B房间动作”的因果链路单例已存在但它是容器而非逻辑调度器观察者可感知事件但原生不具备条件过滤跨域路由能力命令模式擅长执行但缺乏“该不该执行、对谁执行”的决策层。 推荐方案观察者 责任链 命令 的三层协作架构1️⃣ 扩展观察者升级为「事件总线」Event Bus将原SmartHomeController.notify_observers()升级为发布通用事件eventRoomEvent(roombedroom,actionsleep_mode_entered,timestampnow)EventBus.publish(event)# 不再只通知UI/日志而是广播给所有监听者2️⃣ 引入责任链AutomationRuleChain自动化规则链每条规则是一个RuleHandler实现canHandle(event)和handle(event)链式注册支持动态增删按优先级顺序遍历chainRuleChain()chain.add_handler(BedroomSleepRule())# canHandle: event.roombedroom and sleepchain.add_handler(NotifyFamilyRule())# canHandle: event.typesecurity_alertchain.add_handler(BackupLogRule())# canHandle: always True (兜底)BedroomSleepRule.handle(event)→ 解析语义“入睡”关灯关空调关窗帘静音→但这是客厅设备→ 构造跨房间命令new CloseAllInRoomCommand(living_room)→ 调用controller.executeCommand(cmd)复用原有命令执行机制。3️⃣ 增强命令模式支持「目标范围表达式」新增TargetedCommand抽象类子类如CloseAllInRoomCommand(room: str)TurnOffByTypeCommand(device_type: str)// 如 “light”ExecuteIfConditionCommand(condition: Callable, inner_cmd: Command)命令执行时通过单例DeviceRegistry查找匹配设备解耦具体设备位置devicesDeviceRegistry.find_by_room_and_type(living_room,light)fordindevices:d.turnOff()# 并自动 notify_observers()4️⃣ 可选增强规则持久化 条件引擎将规则存为 JSON/YAML如{trigger: {room:bedroom,action:sleep}, actions: [{cmd:close_all, target:living_room}]}运行时加载为RuleHandler实例支持用户App可视化配置拖拽“当卧室入睡 → 关客厅所有灯”。✅ 优势总结维度解决方式解耦性事件总线隔离触发源卧室传感器与执行端客厅设备无需硬编码依赖可扩展性新增规则只需写一个RuleHandler并加入链不影响原有策略/命令/单例逻辑复用性复用命令模式的execute()/undo()、观察者的状态通知、单例的设备注册中心可维护性规则逻辑集中、可测试、可禁用避免在设备类中散落if roombedroom then ...# 示例卧室入睡规则处理器classBedroomSleepRule(RuleHandler):defcanHandle(self,event:RoomEvent)-bool:return(event.roombedroomandevent.actionin[sleep_mode_entered,bedtime_detected])defhandle(self,event:RoomEvent):# 复用已有命令能力cmdCloseAllInRoomCommand(living_room)SmartHomeController.getInstance().executeCommand(cmd)# 自动记录此命令由规则触发支持审计AuditLog.log(fRule-triggered:{cmd})