ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

设计模式17-命令模式:请求的封装与回放

设计模式17-命令模式:请求的封装与回放 命令模式把请求变成可以保存和撤销的对象点击按钮、操作队列、撤销重做、任务调度都要求“动作”本身能像数据一样被保存和传递。命令模式把动作对象化。一、痛点调用者直接绑死接收者一个智能家居系统里用户可能通过面板、语音、定时任务三种方式执行“开灯”“关灯”“调节温度”。如果每种入口都直接调用设备方法if(light-on.equals(action)){light.turnOn();}elseif(ac-up.equals(action)){ac.increaseTemperature();}调用者和设备实现强耦合也没法支持撤销、排队、日志回放。命令模式的回答把每个动作封装成 Command 对象调用者只向命令对象发出“执行”不关心谁真正干活。二、实现命令接口 → 具体命令 → 调用者 → 接收者第一步定义命令接口publicinterfaceCommand{voidexecute();voidundo();}第二步定义接收者publicclassLight{privatebooleanon;publicvoidturnOn(){this.ontrue;System.out.println([灯] 已打开);}publicvoidturnOff(){this.onfalse;System.out.println([灯] 已关闭);}}第三步实现具体命令publicclassLightOnCommandimplementsCommand{privatefinalLightlight;publicLightOnCommand(Lightlight){this.lightlight;}Overridepublicvoidexecute(){light.turnOn();}Overridepublicvoidundo(){light.turnOff();}}publicclassLightOffCommandimplementsCommand{privatefinalLightlight;publicLightOffCommand(Lightlight){this.lightlight;}Overridepublicvoidexecute(){light.turnOff();}Overridepublicvoidundo(){light.turnOn();}}第四步调用者与历史记录importjava.util.ArrayDeque;importjava.util.Deque;publicclassRemoteController{privatefinalDequeCommandhistorynewArrayDeque();publicvoidpress(Commandcommand){command.execute();history.push(command);}publicvoidundo(){if(!history.isEmpty()){history.pop().undo();}}}第五步不同入口复用同一套命令LightlightnewLight();RemoteControllercontrollernewRemoteController();controller.press(newLightOnCommand(light));controller.press(newLightOffCommand(light));controller.undo();// 重新开灯面板、语音、定时任务都只是创建同一个LightOnCommand的入口设备逻辑只存在一处。三、命令模式解决的四类问题问题命令模式的解法调用者与执行者耦合调用者只依赖 Command 接口需要撤销/重做命令对象保存历史并可执行 undo需要延迟执行或定时执行命令对象可以被排队、持久化、定时触发需要记录操作日志每个命令天然是日志条目四、工程化提醒只有动作需要被管理时才引入命令模式普通业务方法直接调用即可别把所有调用都包装成 Command命令粒度要合适一个命令最好对应一个可撤销的业务动作太细会类爆炸太粗会难回滚与真实队列配合生产上可将 Command 序列化到消息队列实现任务解耦和重试。小结命令模式一句话把动作封装成对象让动作可保存、可排队、可撤销。它解耦调用者与接收者也为复杂操作管理提供了统一入口。
返回列表