23种设计模式——命令模式(Command Pattern)
·
✅作者简介:大家好,我是 Meteors., 向往着更加简洁高效的代码写法与编程方式,持续分享Java技术内容。
🍎个人主页:Meteors.的博客
💞当前专栏:设计模式
✨特色专栏:知识分享
🥭本文内容:23种设计模式——命令模式(Command Pattern)
📚 ** ps ** :阅读文章如果有问题或者疑惑,欢迎在评论区提问或指出。
目录
一. 背景
说到命令模式,可能很多人会想到Windows或者Mac的命令行。其实它们的关联并不大,因为命令行界面是一个人机交互系统。的工作原理更多是基于字符串解析 + 程序调用(如 shell 脚本、可执行程序),而不是基于面向对象设计模式中的“命令对象封装”。也没有明确的 Command、Invoker、Receiver 对象模型。下面我将会像你介绍设计模式中的命令模式。
二. 介绍
命令模式(Command Pattern)是一种行为型设计模式,它将请求封装成一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。
三. 核心概念
命令模式的核心思想是将"请求"封装成对象,将发出命令的责任和执行命令的责任分割开,委派给不同的对象。这种模式通过解耦发送者和接收者来实现更灵活的设计。
在命令模式中,通常包含以下角色:
- 命令接口(Command):声明执行操作的接口
- 具体命令(ConcreteCommand):实现命令接口,持有接收者对象的引用
- 接收者(Receiver):执行具体业务逻辑的对象
- 调用者(Invoker):负责调用命令对象执行请求
- 客户端(Client):创建具体命令对象并设置其接收者
四. 代码示例
下面是一个开始和取消命令的实现。它和策略模式很像,但它最大的不同是,它将实际执行的代码都统一到了接收者 。
// 命令接口 public interface Command { void execute(); // 执行命令 void undo(); // 撤销命令(可选) } // 接收者:电灯 public class Light { private String location; public Light(String location) { this.location = location; } public void on() { System.out.println("💡 " + location + " 电灯已打开"); } public void off() { System.out.println("💡 " + location + " 电灯已关闭"); } } // 接收者:空调 public class AirConditioner { private int temperature = 26; public void on() { System.out.println("❄️ 空调已开启"); } public void off() { System.out.println("❄️ 空调已关闭"); } public void setTemperature(int temp) { this.temperature = temp; System.out.println("❄️ 空调温度设置为 " + temp + "°C"); } public int getTemperature() { return temperature; } } // 接收者:电视 public class Television { private int channel = 1; private int volume = 20; public void on() { System.out.println("📺 电视已开启"); } public void off() { System.out.println("📺 电视已关闭"); } public void setChannel(int channel) { this.channel = channel; System.out.println("📺 切换到频道 " + channel); } public void setVolume(int volume) { this.volume = volume; System.out.println("📺 音量设置为 " + volume); } } // 具体命令:开灯命令 public class LightOnCommand implements Command { private Light light; public LightOnCommand(Light light) { this.light = light; } @Override public void execute() { light.on(); } @Override public void undo() { light.off(); } } // 具体命令:关灯命令 public class LightOffCommand implements Command { private Light light; public LightOffCommand(Light light) { this.light = light; } @Override public void execute() { light.off(); } @Override public void undo() { light.on(); } } // 具体命令:开空调命令 public class AirConditionerOnCommand implements Command { private AirConditioner ac; public AirConditionerOnCommand(AirConditioner ac) { this.ac = ac; } @Override public void execute() { ac.on(); ac.setTemperature(24); } @Override public void undo() { ac.off(); } } // 具体命令:设置空调温度 public class AirConditionerTempCommand implements Command { private AirConditioner ac; private int prevTemp; private int newTemp; public AirConditionerTempCommand(AirConditioner ac, int newTemp) { this.ac = ac; this.newTemp = newTemp; } @Override public void execute() { prevTemp = ac.getTemperature(); ac.setTemperature(newTemp); } @Override public void undo() { ac.setTemperature(prevTemp); } } // 具体命令:开电视命令 public class TVOnCommand implements Command { private Television tv; public TVOnCommand(Television tv) { this.tv = tv; } @Override public void execute() { tv.on(); tv.setChannel(5); tv.setVolume(30); } @Override public void undo() { tv.off(); } } // 空命令(避免空指针) public class NoCommand implements Command { @Override public void execute() { // 什么都不做 } @Override public void undo() { // 什么都不做 } } import java.util.Stack; // 调用者:智能遥控器 public class RemoteControl { private Command[] onCommands; // 开按钮命令数组 private Command[] offCommands; // 关按钮命令数组 private Stack<Command> undoStack; // 撤销栈,记录执行过的命令 public RemoteControl() { onCommands = new Command[5]; offCommands = new Command[5]; undoStack = new Stack<>(); // 初始化为空命令 Command noCommand = new NoCommand(); for (int i = 0; i < 5; i++) { onCommands[i] = noCommand; offCommands[i] = noCommand; } } // 设置插槽命令 public void setCommand(int slot, Command onCommand, Command offCommand) { onCommands[slot] = onCommand; offCommands[slot] = offCommand; } // 按下开按钮 public void pressOnButton(int slot) { onCommands[slot].execute(); undoStack.push(onCommands[slot]); // 记录可撤销的命令 } // 按下关按钮 public void pressOffButton(int slot) { offCommands[slot].execute(); undoStack.push(offCommands[slot]); // 记录可撤销的命令 } // 撤销按钮 public void pressUndoButton() { if (!undoStack.isEmpty()) { Command command = undoStack.pop(); command.undo(); } else { System.out.println("⚠️ 没有可撤销的操作"); } } // 显示遥控器配置 public void display() { System.out.println("\n===== 遥控器配置 ====="); for (int i = 0; i < onCommands.length; i++) { System.out.println("插槽 " + i + ": " + onCommands[i].getClass().getSimpleName() + " / " + offCommands[i].getClass().getSimpleName()); } } } import java.util.Arrays; // 宏命令:执行一组命令 public class MacroCommand implements Command { private Command[] commands; public MacroCommand(Command... commands) { this.commands = commands; } @Override public void execute() { System.out.println("🔵 执行宏命令开始..."); for (Command command : commands) { command.execute(); } System.out.println("🔵 宏命令执行完成"); } @Override public void undo() { System.out.println("🔵 撤销宏命令..."); // 反向撤销 for (int i = commands.length - 1; i >= 0; i--) { commands[i].undo(); } } } public class CommandPatternDemo { public static void main(String[] args) { // 创建接收者(家电) Light livingRoomLight = new Light("客厅"); Light kitchenLight = new Light("厨房"); AirConditioner ac = new AirConditioner(); Television tv = new Television(); // 创建命令对象 Command livingRoomLightOn = new LightOnCommand(livingRoomLight); Command livingRoomLightOff = new LightOffCommand(livingRoomLight); Command kitchenLightOn = new LightOnCommand(kitchenLight); Command kitchenLightOff = new LightOffCommand(kitchenLight); Command acOn = new AirConditionerOnCommand(ac); Command acOff = new AirConditionerOffCommand(ac); Command acTemp = new AirConditionerTempCommand(ac, 22); Command tvOn = new TVOnCommand(tv); Command tvOff = new TVOffCommand(tv); // 创建遥控器并设置命令 RemoteControl remote = new RemoteControl(); remote.setCommand(0, livingRoomLightOn, livingRoomLightOff); remote.setCommand(1, kitchenLightOn, kitchenLightOff); remote.setCommand(2, acOn, acOff); remote.setCommand(3, tvOn, tvOff); remote.display(); System.out.println("\n===== 基础操作测试 ====="); // 测试开灯 remote.pressOnButton(0); remote.pressOffButton(0); remote.pressUndoButton(); // 撤销关灯,灯又亮了 System.out.println("\n" + "-".repeat(50)); // 测试空调 remote.pressOnButton(2); remote.pressOnButton(2); // 调温度 remote.pressUndoButton(); // 撤销调温度 System.out.println("\n" + "-".repeat(50)); System.out.println("\n===== 宏命令测试(一键场景)====="); // 创建回家模式宏命令(开客厅灯+开空调) Command homeMode = new MacroCommand(livingRoomLightOn, acOn); remote.setCommand(4, homeMode, homeMode); // 用同一个宏命令 remote.pressOnButton(4); // 执行回家模式 remote.pressUndoButton(); // 撤销回家模式 System.out.println("\n" + "-".repeat(50)); System.out.println("\n===== 命令队列模拟(日志记录)====="); // 模拟命令队列执行 List<Command> commandQueue = Arrays.asList( kitchenLightOn, tvOn, acTemp ); // 记录日志(实际应用中可序列化到文件) System.out.println("📋 执行命令队列(可持久化日志):"); for (Command cmd : commandQueue) { System.out.println(" 执行: " + cmd.getClass().getSimpleName()); cmd.execute(); } } }
五. 使用场景
命令模式用于以下场景:
- 需要将请求调用者和请求接收者解耦
- 需要支持撤销操作
- 需要支持队列操作
- 需要记录操作日志
- 需要支持事务操作
六. 总结
命令模式的主要优点是降低了系统组件之间的耦合度,使得系统更加灵活和易于维护。但同时也要注意,过多的命令类可能会增加系统的复杂性,因此在使用时需要权衡利弊。
最后,
其它设计模式会陆续更新,希望文章对你有所帮助!
更多推荐

所有评论(0)