命令模式是一种行为型设计模式,其核心思想是将 “请求” 封装成一个独立的 “命令对象”,该对象包含执行请求所需的所有信息(如请求的接收者、执行参数等),从而实现 “请求的发送者” 与 “请求的接收者” 解耦 —— 发送者无需知道接收者的具体实现,只需调用命令对象的执行方法即可。
该模式的本质是 “封装请求为对象” ,通过命令对象作为中间载体,支持请求的存储、排队、撤销(Undo)、重做(Redo)等高级功能,同时让发送者和接收者完全独立。
UML结构如下

命令模式的典型应用场景如下:
需要解耦请求发送者与接收者:
- GUI 界面操作:如按钮(调用者)、菜单(调用者)触发 “打开窗口”“保存文件”(命令),窗口 / 文件处理器(接收者)执行实际操作,按钮无需知道窗口如何打开。
- 遥控器控制:如电视遥控器(调用者)的 “开机”“换台” 按钮(命令),电视(接收者)执行对应操作,遥控器无需知道电视的内部电路逻辑。
需要支持命令的撤销 / 重做:
- 文本编辑器:如 “输入文字”“删除文字” 命令,可通过
undo() 撤销上一步操作,通过 redo() 重做已撤销的操作。
- 绘图软件:如 “画直线”“画圆形” 命令,支持撤销最近绘制的图形。
需要批量处理或排队执行命令:
- 任务调度系统:如定时任务(命令)被加入任务队列(调用者维护的命令列表),到时间后批量执行所有任务。
- 数据库事务:如一组 SQL 操作(命令)被封装成事务,要么全部执行(
execute()),要么全部回滚(undo())。
下面我将用 Java 代码实现命令模式,以文件操作(打开和关闭文件)为例,展示命令模式的具体应用。
Command(抽象命令接口):
- 定义了命令的统一接口,包含执行命令的
execute()方法和撤销命令的undo()方法
- 是所有具体命令的抽象父类
1 2 3 4 5 6 7 8 9
| public interface Command { void execute(); void undo(); }
|
具体命令类(OpenFileCommand 和 CloseFileCommand):
- 实现了 Command 接口,持有对命令接收者(FileReceiver)的引用
- 在
execute()方法中调用接收者的相应方法来完成实际操作
- 在
undo()方法中调用接收者的撤销方法来恢复到操作前的状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public class OpenFileCommand implements Command { private FileReceiver fileReceiver; public OpenFileCommand(FileReceiver fileReceiver) { this.fileReceiver = fileReceiver; } @Override public void execute() { fileReceiver.openFile(); } @Override public void undo() { fileReceiver.undoOpenFile(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class CloseFileCommand implements Command { private FileReceiver fileReceiver; public CloseFileCommand(FileReceiver fileReceiver) { this.fileReceiver = fileReceiver; } @Override public void execute() { fileReceiver.closeFile(); } @Override public void undo() { fileReceiver.undoCloseFile(); } }
|
FileReceiver(命令接收者):
- 是实际执行命令的对象,包含打开文件、关闭文件及对应的撤销方法
- 维护文件的状态(是否打开),用于支持撤销操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| public class FileReceiver { private String fileName; private boolean isOpen; public FileReceiver(String fileName) { this.fileName = fileName; this.isOpen = false; } public void openFile() { if (!isOpen) { System.out.println("打开文件:" + fileName); isOpen = true; } else { System.out.println("文件 " + fileName + " 已经处于打开状态"); } } public void closeFile() { if (isOpen) { System.out.println("关闭文件:" + fileName); isOpen = false; } else { System.out.println("文件 " + fileName + " 已经处于关闭状态"); } } public void undoOpenFile() { if (isOpen) { System.out.println("撤销打开文件:" + fileName); closeFile(); } } public void undoCloseFile() { if (!isOpen) { System.out.println("撤销关闭文件:" + fileName); openFile(); } } }
|
ButtonInvoker(命令调用者):
- 持有命令对象的引用,提供
setCommand()方法设置要执行的命令
- 通过
click()方法触发命令的执行,通过clickUndo()方法触发命令的撤销
- 不直接与接收者交互,完全依赖命令对象完成操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class ButtonInvoker { private Command command; public void setCommand(Command command) { this.command = command; } public void click() { if (command != null) { command.execute(); } } public void clickUndo() { if (command != null) { command.undo(); } } }
|
Client(客户端):
- 负责创建接收者、具体命令和调用者对象
- 将接收者注入具体命令,将具体命令注入调用者,完成命令模式的组装
- 触发命令的执行和撤销,测试整个模式的工作流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public class Client { public static void main(String[] args) { FileReceiver fileReceiver = new FileReceiver("example.txt"); Command openCommand = new OpenFileCommand(fileReceiver); Command closeCommand = new CloseFileCommand(fileReceiver); ButtonInvoker button = new ButtonInvoker(); System.out.println("=== 测试打开文件 ==="); button.setCommand(openCommand); button.click(); button.clickUndo(); System.out.println("\n=== 测试关闭文件 ==="); button.setCommand(closeCommand); button.click(); button.click(); button.clickUndo(); } }
|
上述代码执行流程如下:
- 客户端创建接收者对象,它知道如何执行具体的业务操作
- 客户端创建具体命令对象,并将接收者对象注入到命令中
- 客户端将具体命令对象设置到调用者中
- 当调用者触发命令(如按钮被点击)时,调用者调用命令的
execute()方法
- 命令的
execute()方法调用接收者的相应方法,完成实际操作
- 若需要撤销操作,调用者调用命令的
undo()方法,命令会调用接收者的撤销方法
这种设计模式的优势在于:
- 实现了请求发送者(调用者)和接收者之间的解耦
- 支持命令的撤销和重做操作
- 可以很容易地添加新的命令,符合开闭原则
- 便于实现命令的排队执行、日志记录等高级功能