0125_命令模式(Command)
命令模式(Command)
意图
将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化,支持请求的排队、记录日志、撤销等操作。
UML 图

优点
- 解耦调用者和接收者:调用者不需要知道接收者的具体实现
- 支持命令的排队和日志:可以轻松实现命令队列和日志记录
- 支持撤销和重做:通过维护命令历史,可以实现撤销和重做功能
- 易于扩展新命令:新增命令不需要修改现有代码
- 支持宏命令:可以将多个命令组合成一个复合命令
缺点
- 类数量增加:每个命令都需要一个具体的命令类
- 复杂度增加:引入了额外的抽象层,增加了系统复杂度
- 性能开销:命令对象的创建和管理可能带来一定的性能开销
- 内存占用:维护命令历史可能占用较多内存
- 过度设计:简单场景下使用可能显得过于复杂
代码示例
以人类指挥机器人执行各种任务为例:
1. 命令接口 (Command Interface)
// 命令接口
public interface Command {
void execute();
void undo();
String getDescription();
}
2. 接收者 (Receiver) - 机器人
// 接收者 - 机器人
public class Robot {
private String name;
public Robot(String name) {
this.name = name;
}
public void cook(String dish) {
System.out.println("🤖 " + name + " 正在烹饪: " + dish);
}
public void clean(String area) {
System.out.println("🧹 " + name + " 正在打扫: " + area);
}
public void deliver(String item, String location) {
System.out.println("📦 " + name + " 正在配送 " + item + " 到 " + location);
}
public void stopCurrentTask() {
System.out.println("⏹️ " + name + " 停止当前任务");
}
}
3. 具体命令 (Concrete Commands)
// 烹饪命令
public class CookCommand implements Command {
private Robot robot;
private String dish;
public CookCommand(Robot robot, String dish) {
this.robot = robot;
this.dish = dish;
}
@Override
public void execute() {
robot.cook(dish);
}
@Override
public void undo() {
robot.stopCurrentTask();
System.out.println("撤销烹饪: " + dish);
}
@Override
public String getDescription() {
return "烹饪 " + dish;
}
}
// 打扫命令
public class CleanCommand implements Command {
private Robot robot;
private String area;
public CleanCommand(Robot robot, String area) {
this.robot = robot;
this.area = area;
}
@Override
public void execute() {
robot.clean(area);
}
@Override
public void undo() {
robot.stopCurrentTask();
System.out.println("撤销打扫: " + area);
}
@Override
public String getDescription() {
return "打扫 " + area;
}
}
// 配送命令
public class DeliverCommand implements Command {
private Robot robot;
private String item;
private String location;
public DeliverCommand(Robot robot, String item, String location) {
this.robot = robot;
this.item = item;
this.location = location;
}
@Override
public void execute() {
robot.deliver(item, location);
}
@Override
public void undo() {
robot.stopCurrentTask();
System.out.println("撤销配送: " + item + " 到 " + location);
}
@Override
public String getDescription() {
return "配送 " + item + " 到 " + location;
}
}
4. 调用者 (Invoker) - 人类指挥官
// 调用者 - 人类指挥官
public class HumanCommander {
private List<Command> commandHistory = new ArrayList<>();
private Command currentCommand;
public void setCommand(Command command) {
this.currentCommand = command;
}
public void executeCommand() {
if (currentCommand != null) {
System.out.println("🚀 执行命令: " + currentCommand.getDescription());
currentCommand.execute();
commandHistory.add(currentCommand);
}
}
public void undoLastCommand() {
if (!commandHistory.isEmpty()) {
Command lastCommand = commandHistory.remove(commandHistory.size() - 1);
System.out.println("↩️ 撤销命令: " + lastCommand.getDescription());
lastCommand.undo();
}
}
public void showCommandHistory() {
System.out.println("\n📋 命令历史:");
for (int i = 0; i < commandHistory.size(); i++) {
System.out.println((i + 1) + ". " + commandHistory.get(i).getDescription());
}
}
}
5. 客户端代码 (Client Code)
public class CommandPatternDemo {
public static void main(String[] args) {
// 创建接收者 - 机器人
Robot kitchenRobot = new Robot("厨房机器人");
Robot cleaningRobot = new Robot("清洁机器人");
Robot deliveryRobot = new Robot("配送机器人");
// 创建具体命令
Command cookDinner = new CookCommand(kitchenRobot, "红烧牛肉");
Command cleanKitchen = new CleanCommand(cleaningRobot, "厨房");
Command deliverPackage = new DeliverCommand(deliveryRobot, "快递", "A栋101");
Command cookDessert = new CookCommand(kitchenRobot, "水果沙拉");
// 创建调用者 - 人类指挥官
HumanCommander commander = new HumanCommander();
System.out.println("=== 执行一系列命令 ===");
// 执行第一个命令
commander.setCommand(cookDinner);
commander.executeCommand();
// 执行第二个命令
commander.setCommand(cleanKitchen);
commander.executeCommand();
// 执行第三个命令
commander.setCommand(deliverPackage);
commander.executeCommand();
System.out.println("\n=== 撤销上一个命令 ===");
commander.undoLastCommand();
System.out.println("\n=== 执行新命令 ===");
commander.setCommand(cookDessert);
commander.executeCommand();
// 显示命令历史
commander.showCommandHistory();
System.out.println("\n=== 批量撤销 ===");
commander.undoLastCommand(); // 撤销甜点
commander.undoLastCommand(); // 撤销打扫
commander.undoLastCommand(); // 撤销烹饪
commander.showCommandHistory();
}
}
在Java标准库中的应用
命令模式在Java标准库中有多种应用:
- Runnable接口
// Runnable就是一个简单的命令模式实现
Runnable task = () -> System.out.println("执行任务");
new Thread(task).start(); // Invoker
- Swing的Action接口
Action action = new AbstractAction("点击") {
@Override
public void actionPerformed(ActionEvent e) {
// 命令执行
}
};
JButton button = new JButton(action); // Invoker
- 线程池执行命令
ExecutorService executor = Executors.newFixedThreadPool(5);
executor.execute(() -> {
// 命令执行逻辑
}); // Invoker
- Servlet的Service方法
protected void service(HttpServletRequest req, HttpServletResponse resp) {
// 根据请求参数选择不同的命令执行
}
总结
命令模式通过将请求封装为对象,实现了请求的发送者和接收者之间的解耦。在人类与机器人的交互场景中,人类作为调用者只需要发出命令,而不需要了解机器人具体如何执行任务。这种模式支持命令的排队、日志记录、撤销重做等功能,非常适合需要支持事务操作或需要记录操作历史的系统。
该模式的灵活性使得系统可以轻松地扩展新的命令类型,而不需要修改现有的调用者代码。虽然会增加一些类的数量,但在需要复杂命令管理的系统中,这种额外的复杂度是值得的。

浙公网安备 33010602011771号