设计模式之用类来表现_Commond命令模式_命令也是类
前言
Github:https://github.com/HealerJean
一、命令模式(Command Pattern)
1. 模式概述
命令模式 是一种 行为型设计模式,它将 一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
核心思想:“把动作变成对象。”
命令模式 = 请求对象化 + 行为参数化 + 操作可追溯
- 它不是“把方法包装一下”,而是“让动作具备生命”。
类比理解:
- 餐厅点餐:顾客(Client)点菜 → 服务员(Invoker)记录订单(Command)→ 厨师(Receiver)做菜; 订单是独立对象,可存档、取消、批量处理。
- 你提到的军事场景:司令员(Client)下达“进攻”命令 → 传令兵(Invoker)传递命令对象 → 士兵(Receiver)执行;
2. 使用场景
命令模式适用于以下情况:
- 需要 参数化对象行为(用不同命令配置按钮、菜单);
- 需要 支持撤销(Undo)/重做(Redo) 操作;
- 需要 将请求放入队列(如任务调度、线程池);
- 需要 记录操作日志(用于事务回滚或审计);
- 需要 组合多个命令为宏命令(Macro Command)。
典型应用:
- GUI 菜单/按钮的点击事件(每个按钮绑定一个命令);
- 文本编辑器的撤销功能;
- 游戏中的技能系统(每个技能是一个命令);
- 事务性操作(如数据库事务回滚)。
3. 示例程序:军事指挥系统(优化版)
1)命令接口 Command
/**
* 命令接口(Command)
*/
public interface Command {
void execute(); // 执行
void undo(); // 撤销(可选,但常用)
}
2)接收者 Soldier
/**
* 接收者(Receiver)
* 真正执行动作的对象
*/
public class Soldier {
private String actionHistory = "";
public void attack(String target) {
System.out.println("【士兵】正在攻击目标: " + target);
actionHistory = "attack:" + target;
}
public void defend() {
System.out.println("【士兵】进入防御状态");
actionHistory = "defend";
}
public void recall() {
System.out.println("【士兵】撤销上一次操作: " + actionHistory);
}
}
3)具体命令类
a、攻击命令
public class AttackCommand implements Command {
private final Soldier soldier;
private final String target;
public AttackCommand(Soldier soldier, String target) {
this.soldier = soldier;
this.target = target;
}
@Override
public void execute() {
soldier.attack(target);
}
@Override
public void undo() {
soldier.recall();
}
}
b、防御命令
public class DefendCommand implements Command {
private final Soldier soldier;
public DefendCommand(Soldier soldier) {
this.soldier = soldier;
}
@Override
public void execute() {
soldier.defend();
}
@Override
public void undo() {
soldier.recall();
}
}
4)调用者 General
import java.util.ArrayDeque;
import java.util.Deque;
/**
* 调用者(Invoker)
* 可支持命令队列和撤销栈
*/
public class General {
private final Deque<Command> history = new ArrayDeque<>();
public void issueCommand(Command command) {
command.execute();
history.push(command); // 记录历史,用于撤销
}
public void undoLastCommand() {
if (!history.isEmpty()) {
Command last = history.pop();
last.undo();
} else {
System.out.println("【司令员】无可撤销的命令");
}
}
}
5)客户端测试 Main
- 命令可撤销;
Invoker(General)完全不知道 Soldier 的存在;- 新增命令(如
RetreatCommand)无需修改现有代码。
public class Main {
public static void main(String[] args) {
Soldier soldier = new Soldier();
General general = new General();
// 下达命令
general.issueCommand(new AttackCommand(soldier, "敌方碉堡"));
general.issueCommand(new DefendCommand(soldier));
System.out.println("\n--- 撤销上一条命令 ---");
general.undoLastCommand();
System.out.println("\n--- 再次撤销 ---");
general.undoLastCommand();
}
}
输出:
【士兵】正在攻击目标: 敌方碉堡
【士兵】进入防御状态
--- 撤销上一条命令 ---
【士兵】撤销上一次操作: defend
--- 再次撤销 ---
【士兵】撤销上一次操作: attack:敌方碉堡
6)模式角色
- 解耦:
Invoker不知道Receiver是谁; - 可扩展:新增命令只需实现
Command接口; - 可组合:多个命令可组成复合命令。
| 角色 | 职责 | 示例 |
|---|---|---|
| Command(命令接口) | 声明执行操作的接口 | Command |
| ConcreteCommand(具体命令) | 绑定接收者,实现 execute() |
AttackCommand |
| Receiver(接收者) | 真正执行业务逻辑的对象 | Soldier |
| Invoker(调用者) | 持有命令对象,触发执行(不关心具体逻辑) | General / Button |
| Client(客户端) | 创建命令对象,并设置接收者 | 应用启动时绑定命令 |
4、FQA
1)模式优点
- 解耦调用者与接收者;
- 支持命令的排队、日志、撤销、重做;
- 易于扩展新命令(符合开闭原则);
- 可组合命令(如宏命令:一键执行“攻击+防御”)。
2)注意事项
- 类数量增加(每个命令一个类);
- 简单场景可能过度设计;
- 撤销操作需 Receiver 支持状态回滚。


