文章目录
- [1. 生活中的例子](#1. 生活中的例子)
-
- [1.1 餐厅点餐系统 🍽️](#1.1 餐厅点餐系统 🍽️)
- [1.2 遥控器控制家电 📺](#1.2 遥控器控制家电 📺)
- [1.3 游戏手柄 🎮](#1.3 游戏手柄 🎮)
- [2. 代码中的例子](#2. 代码中的例子)
-
- [2.1 灯光开关控制](#2.1 灯光开关控制)
- [2.2 智能家居系统](#2.2 智能家居系统)
- [2.3 支持队列和日志的命令模式](#2.3 支持队列和日志的命令模式)
- [3. 归纳总结](#3. 归纳总结)
-
- [3.1 核心要点总结](#3.1 核心要点总结)
- [3.2 重要但未提及的知识点](#3.2 重要但未提及的知识点)
- [3.3 实际应用建议](#3.3 实际应用建议)
1. 生活中的例子
1.1 餐厅点餐系统 🍽️
想象你去餐厅吃饭:
- 你(客户端):想要吃牛排和沙拉
- 服务员(调用者):拿着点餐单记录你的需求
- 点餐单(命令对象):包含具体菜品和烹饪要求
- 厨师(接收者):实际做菜的人
关键理解:你不需要直接跑到厨房告诉厨师怎么做,服务员也不需要知道具体烹饪方法。点餐单这个"命令对象"把请求和具体执行解耦了。
1.2 遥控器控制家电 📺
电视遥控器的工作方式:
- 遥控器按钮(命令):比如"音量+""换台"
- 遥控器(调用者):只知道按按钮,不知道内部原理
- 电视(接收者):实际执行操作
- 你(客户端):按按钮的人
核心思想:同样的遥控器可以控制不同品牌的电视,因为命令被抽象化了。
1.3 游戏手柄 🎮
游戏手柄设计:
- A键、B键(命令):绑定不同游戏动作
- 手柄(调用者):只负责触发命令
- 游戏角色(接收者):执行具体动作
- 按键配置(客户端):可以随时改变按键功能
设计优势:你可以随时改变按键映射,而不需要修改手柄硬件或游戏代码。
2. 代码中的例子
2.1 灯光开关控制
java
// 1. 命令接口(所有命令的通用接口)
interface Command {
void execute();
void undo(); // 支持撤销操作
}
// 2. 接收者(实际执行操作的对象)
class Light {
private boolean isOn = false;
public void turnOn() {
isOn = true;
System.out.println("💡 灯已打开");
}
public void turnOff() {
isOn = false;
System.out.println("💡 灯已关闭");
}
public boolean isOn() {
return isOn;
}
}
// 3. 具体命令类
class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOn();
}
@Override
public void undo() {
light.turnOff();
}
}
class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOff();
}
@Override
public void undo() {
light.turnOn();
}
}
// 4. 调用者(触发命令的对象)
class RemoteControl {
private Command command;
private Command lastCommand; // 记录上次命令,用于撤销
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
lastCommand = command;
command.execute();
}
public void pressUndo() {
if (lastCommand != null) {
lastCommand.undo();
lastCommand = null;
}
}
}
// 5. 客户端使用
public class CommandPatternDemo {
public static void main(String[] args) {
// 创建接收者
Light livingRoomLight = new Light();
// 创建具体命令
Command lightOn = new LightOnCommand(livingRoomLight);
Command lightOff = new LightOffCommand(livingRoomLight);
// 创建调用者
RemoteControl remote = new RemoteControl();
// 测试开灯
System.out.println("=== 测试开灯 ===");
remote.setCommand(lightOn);
remote.pressButton(); // 输出:💡 灯已打开
// 测试撤销
System.out.println("\n=== 测试撤销 ===");
remote.pressUndo(); // 输出:💡 灯已关闭
// 测试关灯
System.out.println("\n=== 测试关灯 ===");
remote.setCommand(lightOff);
remote.pressButton(); // 输出:💡 灯已关闭
}
}
2.2 智能家居系统
java
// 宏命令:一次执行多个命令
class MacroCommand implements Command {
private List<Command> commands = new ArrayList<>();
public void addCommand(Command command) {
commands.add(command);
}
@Override
public void execute() {
System.out.println("🚀 执行宏命令序列:");
for (Command cmd : commands) {
cmd.execute();
}
}
@Override
public void undo() {
System.out.println("↩️ 撤销宏命令序列:");
// 反向执行撤销
List<Command> reversed = new ArrayList<>(commands);
Collections.reverse(reversed);
for (Command cmd : reversed) {
cmd.undo();
}
}
}
// 更多接收者类
class TV {
private boolean isOn = false;
private int volume = 20;
public void turnOn() {
isOn = true;
System.out.println("📺 电视已打开,音量:" + volume);
}
public void turnOff() {
isOn = false;
System.out.println("📺 电视已关闭");
}
public void setVolume(int volume) {
this.volume = volume;
System.out.println("📺 电视音量设置为:" + volume);
}
}
class AirConditioner {
private boolean isOn = false;
private int temperature = 25;
public void turnOn(int temp) {
isOn = true;
this.temperature = temp;
System.out.println("❄️ 空调已打开,温度:" + temp + "°C");
}
public void turnOff() {
isOn = false;
System.out.println("❄️ 空调已关闭");
}
}
// 使用示例
public class SmartHomeDemo {
public static void main(String[] args) {
// 创建设备
Light light = new Light();
TV tv = new TV();
AirConditioner ac = new AirConditioner();
// 创建具体命令(使用匿名类简化)
Command lightOn = () -> light.turnOn();
Command tvOn = () -> {
tv.turnOn();
tv.setVolume(30);
};
Command acOn = () -> ac.turnOn(22);
// 创建"回家模式"宏命令
MacroCommand homeMode = new MacroCommand();
homeMode.addCommand(lightOn);
homeMode.addCommand(tvOn);
homeMode.addCommand(acOn);
// 执行回家模式
System.out.println("=== 执行回家模式 ===");
homeMode.execute();
System.out.println("\n=== 撤销回家模式 ===");
homeMode.undo();
}
}
2.3 支持队列和日志的命令模式
java
import java.util.LinkedList;
import java.util.Queue;
// 命令管理器(支持队列和日志)
class CommandManager {
private Queue<Command> commandQueue = new LinkedList<>();
private List<Command> commandHistory = new ArrayList<>();
// 添加命令到队列
public void addToQueue(Command command) {
commandQueue.offer(command);
}
// 批量执行队列中的命令
public void processQueue() {
System.out.println("🔄 处理命令队列...");
while (!commandQueue.isEmpty()) {
Command cmd = commandQueue.poll();
cmd.execute();
commandHistory.add(cmd);
}
}
// 显示执行历史
public void showHistory() {
System.out.println("📜 命令执行历史:");
for (int i = 0; i < commandHistory.size(); i++) {
System.out.println((i + 1) + ". " + commandHistory.get(i).getClass().getSimpleName());
}
}
}
// 延迟执行命令
class DelayedCommand implements Command {
private Command command;
private long delayMillis;
public DelayedCommand(Command command, long delayMillis) {
this.command = command;
this.delayMillis = delayMillis;
}
@Override
public void execute() {
try {
System.out.println("⏳ 等待 " + delayMillis + "ms 后执行...");
Thread.sleep(delayMillis);
command.execute();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void undo() {
command.undo();
}
}
// 使用示例
public class AdvancedCommandDemo {
public static void main(String[] args) {
Light light = new Light();
CommandManager manager = new CommandManager();
// 创建各种命令
Command cmd1 = new LightOnCommand(light);
Command cmd2 = new DelayedCommand(new LightOffCommand(light), 1000);
Command cmd3 = () -> System.out.println("🔔 自定义命令:播放门铃声音");
// 添加到队列
manager.addToQueue(cmd1);
manager.addToQueue(cmd2);
manager.addToQueue(cmd3);
// 处理队列
manager.processQueue();
// 查看历史
manager.showHistory();
}
}
3. 归纳总结
3.1 核心要点总结
-
四大角色:
- Command(命令):定义执行操作的接口
- ConcreteCommand(具体命令):绑定接收者和动作
- Invoker(调用者):请求的发送者
- Receiver(接收者):知道如何执行操作
-
三大优势:
- ✅ 解耦:调用者与接收者完全独立
- ✅ 可扩展:新命令很容易添加
- ✅ 支持高级功能:撤销、重做、队列、日志等
-
两大应用场景:
- 需要将操作参数化的场景
- 需要支持撤销/重做、事务处理的场景
3.2 重要但未提及的知识点
- 命令模式 vs 策略模式 :
- 命令模式:关注"做什么"和"什么时候做"
- 策略模式:关注"怎么做"
- 命令对象的生命周期 :
- 命令对象可以是一次性的,也可以是可重用的
- 考虑使用对象池管理频繁创建的命令对象
3.线程安全问题:
java
// 线程安全的命令管理器
class ThreadSafeCommandManager {
private final Queue<Command> queue = new ConcurrentLinkedQueue<>();
public synchronized void addCommand(Command cmd) {
queue.offer(cmd);
}
}
- 结合其他模式 :
- 组合模式:创建宏命令(复合命令)
- 备忘录模式:实现更复杂的撤销/重做
- 原型模式:克隆命令对象
3.3 实际应用建议
-
何时使用:
- GUI 中的按钮和菜单项
- 事务系统(数据库操作)
- 任务调度系统
- 网络请求队列
-
性能考虑:
java
// 使用享元模式共享接收者
class CommandFactory {
private static Map<String, Command> commandPool = new HashMap<>();
public static Command getCommand(String key, Receiver receiver) {
return commandPool.computeIfAbsent(key,
k -> new ConcreteCommand(receiver));
}
}
- 现代Java特性优化
java
// 使用函数式接口简化
@FunctionalInterface
interface SimpleCommand {
void execute();
default SimpleCommand andThen(SimpleCommand after) {
return () -> {
execute();
after.execute();
};
}
}
// 使用示例
SimpleCommand cmd = () -> System.out.println("Hello")
.andThen(() -> System.out.println("World"));