1 应用场景
- 将特定方法转换为独立的对象;
- 将操作放入队列中、操作的执行或者远程执行操作;序列化操作,从而存入文件、数据库;延迟命令执行。
- 操作回滚功能。这种方法有两个缺点。首先,程序状态的保存功能并不容易实现,因为部分状态可能是私有的。你可以使用备忘录模式来在一定程度上解决这个问题。其次,备份状态可能会占用大量内存。因此,有时你需要借助另一种实现方式: 命令无需恢复原始状态,而是执行反向操作。反向操作也有代价: 它可能会很难甚至是无法实现。
2 优缺点
优点:
- 单一职责原则。你可以解耦触发和执行操作的类。
- 开闭原则。你可以在不修改已有客户端代码的情况下在程序中创建新的命令。
- 你可以实现撤销和恢复功能。
- 你可以实现操作的延迟执行。
- 你可以将一组简单命令组合成一个复杂命令。
缺点:
- 代码可能会变得更加复杂,因为你在发送者和接收者之间增加了一个全新的层次。
3 经典应用例子
java.lang.Runnable的所有实现javax.swing.Action的所有实现
4 命令模式
将一个请求(命令)封装成一个对象,从而让我们可以使用 不同的请求参数化其他对象(依赖注入),且支持请求的排队执行、记录日志、撤销等功能(附加控制)。
落实到编码实现,命令模式用的最核心的实现手段就是:** 将函数封装成对象以便传递 ,当你所用的编程语言不支持函数作为参数传递,就可以考虑用下它了。把函数封装成对象,还可以存储**,控制执行,这也是命令模式的优点~

- 发送者 (Sender)——亦称 “触发者 (Invoker)”——类负责对请求进行初始化,其中必须包含一个成员变量来存储对于命令对象的引用。发送者触发命令,而不向接收者直接发送请求。注意,发送者并不负责创建命令对象: 它通常会通过构造函数从客户端处获得预先生成的命令。
- 命令 (Command) 接口通常仅声明一个执行命令的方法。
- 具体命令 (Concrete Commands) 会实现各种类型的请求。具体命令自身并不完成工作,而是会将调用委派给一个业务逻辑对象。但为了简化代码,这些类可以进行合并。
接收对象执行方法所需的参数可以声明为具体命令的成员变量。你可以将命令对象设为不可变,仅允许通过构造函数对这些成员变量进行初始化。 - 接收者 (Receiver) 类包含部分业务逻辑。几乎任何对象都可以作为接收者。绝大部分命令只处理如何将请求传递到接收者的细节,接收者自己会完成实际的工作。
- 客户端 (Client) 会创建并配置具体命令对象。客户端必须将包括接收者实体在内的所有请求参数传递给命令的构造函数。此后,生成的命令就可以与一个或多个发送者相关联了。
5 实现代码
//命令抽象类
public abstract class Command {
public Editor editor;
private String backup;
Command(Editor editor) { this.editor = editor; }
void backup() { backup = editor.textField.getText(); }
public void undo() { editor.textField.setText(backup); }
public abstract boolean execute();
}
//命令实体类
public class CopyCommand extends Command {
public CopyCommand(Editor editor) { super(editor); }
@Override
public boolean execute() {
editor.clipboard = editor.textField.getSelectedText();
return false;
}
}
public class PasteCommand extends Command {
public PasteCommand(Editor editor) { super(editor); }
@Override
public boolean execute() {
if (editor.clipboard == null || editor.clipboard.isEmpty()) return false;
backup();
editor.textField.insert(editor.clipboard, editor.textField.getCaretPosition());
return true;
}
}
//命令历史
public class CommandHistory {
private Stack<Command> history = new Stack<>();
public void push(Command c) { history.push(c); }
public Command pop() { return history.pop(); }
public boolean isEmpty() { return history.isEmpty(); }
}
//客户端
private CommandHistory history = new CommandHistory(); //定义命令历史
ctrlC.addActionListener(new ActionListener() { // 绑定执行操作
@Override
public void actionPerformed(ActionEvent e) {
executeCommand(new CopyCommand(editor));
}
});
ctrlX.addActionListener(new ActionListener() {// 绑定执行操作
@Override
public void actionPerformed(ActionEvent e) {
executeCommand(new CutCommand(editor));
}
});
ctrlZ.addActionListener(new ActionListener() {// 绑定执行操作
@Override
public void actionPerformed(ActionEvent e) {
undo();
}
});
private void executeCommand(Command command) {
if (command.execute()) {
history.push(command);
}
}
private void undo() {
if (history.isEmpty()) return;
Command command = history.pop();
if (command != null) {
command.undo();
}
}