Java 23 种设计模式:从踩坑到精通 | 番外:命令模式 —— 仓储设备控制实战
Java 23 种设计模式从踩坑到精通 | 番外命令模式 —— 仓储设备控制实战摘要命令模式将“请求”封装为对象从而让你可以用不同的请求对客户端参数化、对请求排队或记录日志并天然支持撤销操作。本文结合智能仓储设备控制系统的场景完整展示如何用命令模式实现对传送带、分拣机等设备的远程控制和撤销操作并与策略模式深度对比帮你掌握“将行为对象化”的设计精髓。️本文阅读地图3 分钟速览为什么设备控制不能直接调用设备方法✅ 命令模式核心角色调用者、抽象命令、具体命令、接收者手写仓储调度中心启动/停止设备支持多步撤销 命令 vs 策略行为封装 vs 算法替换 面试必问“命令模式和策略模式有什么区别Runnable用了哪个”《Java 23 种设计模式从踩坑到精通》开篇系列介绍与目录 正篇命令模式 Command —— 把操作封装成对象实现撤销与排队 当前番外 · 命令模式 × 仓储设备控制 返回系列总目录1. 仓储设备控制的痛点在智能仓库中有传送带、分拣机、堆垛机等多种设备。操作员通过一个中央控制台来管理这些设备的启停。如果直接在控制台类中调用设备方法if(button.equals(start_conveyor)){conveyor1.start();}elseif(button.equals(stop_sorter)){sorter1.stop();}这种写法将控制台与具体设备紧耦合新增设备或修改操作逻辑都需要修改控制台代码。更复杂的是操作员希望控制台支持撤销上一步操作和一键批量操作——这用if-else几乎无法优雅实现。命令模式的解决思路将“启动设备”和“停止设备”这些操作封装为独立的命令对象控制台只持有命令并触发执行不关心命令内部是哪个设备、如何执行。所有执行过的命令记录在栈中撤销时只需弹出栈顶并调用undo()。1.1 你的场景该不该用命令模式判断标准是 → 用命令模式否 → 用其他方式需要将操作的发起者与执行者解耦✅❌需要支持撤销/重做、命令队列、宏命令✅❌需要在运行时动态指定、排列或执行请求✅❌只有简单的调用无需撤销或排队❌直接调用即可2. 命令模式 UML仓储设备控制场景3. 完整源码实现3.1 抽象命令接口 (Command)/** * 抽象命令声明执行和撤销操作 */publicinterfaceCommand{voidexecute();voidundo();}白话所有命令都必须能“执行”和“撤销”。这就是命令模式的灵魂——命令不仅是“做什么”还要知道“怎么反悔”。3.2 接收者仓库设备基类 (WarehouseDevice)/** * 接收者仓库设备基类 */publicabstractclassWarehouseDevice{protectedStringname;protectedbooleanisRunning;publicWarehouseDevice(Stringname){this.namename;this.isRunningfalse;}publicabstractvoidstart();publicabstractvoidstop();publicStringgetName(){returnname;}publicbooleanisRunning(){returnisRunning;}}3.3 具体接收者传送带 (ConveyorBelt)/** * 具体接收者传送带设备 */publicclassConveyorBeltextendsWarehouseDevice{publicConveyorBelt(Stringname){super(name);}Overridepublicvoidstart(){isRunningtrue;System.out.println( name 启动传送带开始运转速度 1.5m/s);}Overridepublicvoidstop(){isRunningfalse;System.out.println( name 停止传送带已关闭);}}3.4 具体接收者分拣机 (SortingMachine)/** * 具体接收者分拣机设备 */publicclassSortingMachineextendsWarehouseDevice{publicSortingMachine(Stringname){super(name);}Overridepublicvoidstart(){isRunningtrue;System.out.println( name 启动分拣机开始工作处理能力 500件/分钟);}Overridepublicvoidstop(){isRunningfalse;System.out.println( name 停止分拣机已关闭);}}白话这些设备就是“真正干活的”——传送带知道怎么启动和停止自己分拣机也知道。它们不关心是谁发出的指令。3.5 具体命令启动/停止设备命令/** * 具体命令启动设备 */publicclassStartDeviceCommandimplementsCommand{privateWarehouseDevicedevice;publicStartDeviceCommand(WarehouseDevicedevice){this.devicedevice;}Overridepublicvoidexecute(){device.start();}Overridepublicvoidundo(){device.stop();}}/** * 具体命令停止设备 */publicclassStopDeviceCommandimplementsCommand{privateWarehouseDevicedevice;publicStopDeviceCommand(WarehouseDevicedevice){this.devicedevice;}Overridepublicvoidexecute(){device.stop();}Overridepublicvoidundo(){device.start();}}白话启动命令的撤销就是停止停止命令的撤销就是重新启动——这是最简洁的撤销实现。3.6 调用者设备调度中心 (DeviceScheduler)importjava.util.Stack;/** * 调用者设备调度中心遥控器 */publicclassDeviceScheduler{privateStackCommandcommandHistorynewStack();publicvoidexecuteCommand(Commandcommand){command.execute();commandHistory.push(command);System.out.println( ✅ 命令已执行当前历史记录commandHistory.size() 条\n);}publicvoidundoLastCommand(){if(commandHistory.isEmpty()){System.out.println( ⚠️ 无命令可撤销\n);return;}CommandcommandcommandHistory.pop();command.undo();System.out.println( ↩️ 已撤销上一个命令剩余历史记录commandHistory.size() 条\n);}}白话调度中心就像遥控器——它只管按下“执行”或“撤销”按钮完全不知道控制的是传送带还是分拣机。所有执行过的命令压入栈中撤销时弹出栈顶。3.7 客户端测试publicclassClient{publicstaticvoidmain(String[]args){System.out.println( 智能仓储设备控制系统命令模式\n);ConveyorBeltconveyor1newConveyorBelt(传送带A-1);ConveyorBeltconveyor2newConveyorBelt(传送带B-2);SortingMachinesorter1newSortingMachine(分拣机S-1);DeviceSchedulerschedulernewDeviceScheduler();// 场景1~3正常执行scheduler.executeCommand(newStartDeviceCommand(conveyor1));scheduler.executeCommand(newStartDeviceCommand(sorter1));scheduler.executeCommand(newStopDeviceCommand(conveyor1));// 场景4撤销停止 → 传送带恢复运行scheduler.undoLastCommand();// 场景5批量启动scheduler.executeCommand(newStartDeviceCommand(conveyor2));scheduler.executeCommand(newStartDeviceCommand(sorter1));// 场景6紧急连续撤销scheduler.undoLastCommand();scheduler.undoLastCommand();}}4. 运行结果 智能仓储设备控制系统命令模式 传送带A-1 启动传送带开始运转速度 1.5m/s ✅ 命令已执行当前历史记录1 条 分拣机S-1 启动分拣机开始工作处理能力 500件/分钟 ✅ 命令已执行当前历史记录2 条 传送带A-1 停止传送带已关闭 ✅ 命令已执行当前历史记录3 条 传送带A-1 启动传送带开始运转速度 1.5m/s ↩️ 已撤销上一个命令剩余历史记录2 条 传送带B-2 启动传送带开始运转速度 1.5m/s ✅ 命令已执行当前历史记录3 条 分拣机S-1 启动分拣机开始工作处理能力 500件/分钟 ✅ 命令已执行当前历史记录4 条 分拣机S-1 停止分拣机已关闭 ↩️ 已撤销上一个命令剩余历史记录3 条 传送带B-2 停止传送带已关闭 ↩️ 已撤销上一个命令剩余历史记录2 条5. 核心角色回顾角色职责对应代码Command定义执行和撤销的接口CommandConcreteCommand绑定接收者与动作StartDeviceCommand/StopDeviceCommandReceiver真正执行具体业务逻辑ConveyorBelt/SortingMachineInvoker持有命令触发执行与撤销DeviceScheduler6. 命令模式 vs 策略模式对比项命令模式策略模式意图封装请求为对象支持撤销/队列封装算法族使其可相互替换是否支持撤销✅ 核心特性❌ 通常不需要典型应用Runnable、仓储设备控制、事务回滚Comparator、支付方式、促销策略一句话记忆命令模式是“行为对象化”——把操作变成对象能执行也能撤销策略模式是“算法对象化”——把算法变成对象能灵活替换。7. 命令模式的优缺点优点缺点调用者与接收者完全解耦每个命令一个类命令多时类数量膨胀天然支持撤销/重做、宏命令设计复杂度增加角色较多符合开闭原则新增命令无需修改现有代码命令对象持有状态时需注意线程安全8. 六大设计原则体现原则体现单一职责命令只负责请求封装设备只负责执行开闭原则新增命令无需修改调度中心或设备里氏替换所有命令可替换Command接口依赖倒置调度中心依赖抽象Command接口隔离Command只有execute()和undo()迪米特法则调度中心只与命令交互不知设备细节附 命令模式 UML源码仓储设备控制场景startuml title Java 23 种设计模式从踩坑到精通 footer 折哥 | 智能物流与Java实战 1. 全局样式配置 skinparam backgroundColor #FEFEFE skinparam shadowing false skinparam classBorderColor #333333 skinparam classFontColor #1A1A1A skinparam classFontSize 14 skinparam noteFontSize 12 skinparam noteFontColor #555555 skinparam arrowColor #555555 skinparam classBackgroundColor #F9F9F9 skinparam interface { BackgroundColor #E8F5E9 BorderColor #2E7D32 } 2. 调用者遥控器/调度中心 class Invoker { - command : Command setCommand(Command) executeCommand() undoLastCommand() } note right of Invoker b调用者调度中心/b -- 持有命令对象触发执行 不关心具体执行细节 支持撤销操作 end note 3. 抽象命令 interface Command { execute() undo() } note right of Command b抽象命令/b -- 声明执行和撤销操作 所有具体命令都实现此接口 end note 4. 具体命令开启 class LightOnCommand implements Command { - light : Light execute() undo() } note right of LightOnCommand b具体命令开启/b -- 持有接收者引用 执行时调用接收者的on() 撤销时调用接收者的off() end note 5. 具体命令关闭 class LightOffCommand implements Command { - light : Light execute() undo() } note right of LightOffCommand b具体命令关闭/b -- 持有接收者引用 执行时调用接收者的off() 撤销时调用接收者的on() end note 6. 接收者 class Light { on() off() } note right of Light b接收者执行者/b -- 真正执行具体业务逻辑 与命令解耦无需知道谁调用 end note 7. 关系连线 Invoker o-- Command : 持有命令 LightOnCommand -- Light : 调用 LightOffCommand -- Light : 调用 LightOnCommand ..| Command : 实现 LightOffCommand ..| Command : 实现 enduml 《Java 23 种设计模式从踩坑到精通》快速导航开篇系列介绍与目录正篇命令模式 Command —— 把操作封装成对象实现撤销与排队当前番外 · 命令模式 × 仓储设备控制你在这里创建型模式汇总结构型模式汇总行为型模式汇总 关注《Java 23 种设计模式从踩坑到精通》用 25 篇文章彻底吃透设计模式。福利预告全系列代码及 UML 源码将在完结时统一打包开放点击「关注」「收藏」第一时间获取。 除了设计模式我也在深挖智能物流实战WMS、托盘调度、机器学习落地。欢迎点击头像看看专栏 《出版社物流WMS智能调度实战》、《电商多平台电子面单对接实战》。技术相通思路可鉴。