Java设计模式之命令模式详解
Java设计模式之命令模式详解
一、命令模式核心思想
核心目标:将请求封装为对象,使请求的发送者与接收者解耦。支持请求的排队、记录、撤销等操作,如同餐厅点餐系统:顾客(发送者)→ 订单(命令对象)→ 厨师(接收者)。
二、命令模式类图(Mermaid)
三、代码实现示例
1. 智能家居控制场景
// 接收者:灯光
class Light {private boolean isOn = false;public void turnOn() {isOn = true;System.out.println("灯光已打开");}public void turnOff() {isOn = false;System.out.println("灯光已关闭");}public boolean isOn() { return isOn; }
}// 命令接口
interface Command {void execute();void undo();
}// 具体命令:开灯
class LightOnCommand implements Command {private Light light;public LightOnCommand(Light light) {this.light = light;}public void execute() {light.turnOn();}public void undo() {light.turnOff();}
}// 调用者:遥控器按钮
class RemoteControlButton {private Command command;private Command lastCommand;public void setCommand(Command command) {this.command = command;}public void pressButton() {command.execute();lastCommand = command;}public void pressUndo() {if (lastCommand != null) {lastCommand.undo();lastCommand = null;}}
}// 客户端调用
public class Client {public static void main(String[] args) {Light livingRoomLight = new Light();Command lightOn = new LightOnCommand(livingRoomLight);RemoteControlButton button = new RemoteControlButton();button.setCommand(lightOn);button.pressButton(); // 输出:灯光已打开button.pressUndo(); // 输出:灯光已关闭}
}
四、模式优缺点分析
✅ 优势
- 解耦请求者与执行者:发送者无需知道接收者细节
- 支持高级操作:轻松实现撤销/重做、事务、队列等功能
- 灵活扩展:新增命令无需修改已有代码
- 组合命令:支持宏命令(批量执行)
❌ 缺点
- 类数量增加:每个命令都需要单独类
- 过度设计风险:简单操作可能不适用
五、典型应用场景
- GUI操作:菜单项点击事件处理
- 事务系统:数据库操作回滚
- 任务队列:线程池任务调度
- 宏命令:批量执行操作(如IDE快捷键)
- 游戏控制:角色动作的撤销/重做
六、Mermaid序列图(命令执行流程)
七、命令模式 vs 其他模式
对比模式 | 核心区别 |
---|---|
策略模式 | 封装算法,行为可替换 |
职责链模式 | 请求沿链传递直到被处理 |
备忘录模式 | 保存对象状态用于恢复 |
八、高级应用技巧
1. 宏命令(批量操作)
class MacroCommand implements Command {private List<Command> commands = new ArrayList<>();public void add(Command cmd) {commands.add(cmd);}public void execute() {commands.forEach(Command::execute);}public void undo() {// 逆序执行撤销for (int i = commands.size()-1; i >=0; i--) {commands.get(i).undo();}}
}// 使用示例
MacroCommand partyMode = new MacroCommand();
partyMode.add(new LightOnCommand(light));
partyMode.add(new MusicPlayCommand(speaker));
partyMode.execute(); // 同时执行开灯和播放音乐
2. 命令历史记录(支持多级撤销)
class CommandHistory {private Stack<Command> history = new Stack<>();public void push(Command cmd) {history.push(cmd);}public Command pop() {return history.pop();}public void undoAll() {while (!history.isEmpty()) {history.pop().undo();}}
}
九、实际框架应用案例
1. Java Swing的Action接口
2. Spring的JdbcTemplate
// 命令模式变体:模板方法+回调命令
jdbcTemplate.execute(new ConnectionCallback<Object>() {public Object doInConnection(Connection conn) {// 执行SQL命令return null;}
});
十、常见问题解答
Q1:如何防止命令对象膨胀?
- 使用Lambda表达式(Java 8+)
button.setCommand(() -> light.turnOn());
Q2:如何处理命令参数?
class DimLightCommand implements Command {private Light light;private int prevBrightness;private int newBrightness;public DimLightCommand(Light light, int brightness) {this.light = light;this.newBrightness = brightness;}public void execute() {prevBrightness = light.getBrightness();light.setBrightness(newBrightness);}public void undo() {light.setBrightness(prevBrightness);}
}
Q3:命令模式如何支持异步?
class AsyncCommand implements Command {private Command command;public void execute() {new Thread(command::execute).start();}
}
如果文章对您有帮助,请帮忙点关注支持一下吧,谢谢啦!