命令模式(Command Pattern)
概念
命令模式是一种行为型设计模式,它将请求封装成一个对象,从而使您可以使用不同的请求对客户进行参数化,排队请求,以及支持可撤销操作。通过这种模式,调用操作的对象和实际执行操作的对象解耦,使得系统更加灵活。
应用场景
-
请求参数化:在某些情况下,您可能需要将请求参数化并传递给多个调用者。命令模式允许将请求封装为对象,便于传递和存储。
-
队列和日志:可以将请求存储在队列中,稍后处理。这在异步执行或日志记录系统中非常有用。
-
撤销操作:命令对象可以保存请求执行前的状态,从而支持撤销和重做操作。
-
宏命令:当需要执行一系列操作时,可以将它们封装成一个宏命令,以便一次性执行。
注意点
-
命令对象数量:如果系统中存在大量不同请求,命令对象的数量会显著增加,从而增加系统复杂性。
-
状态管理:需要确保命令对象能够保存执行前后的状态,以便实现撤销功能。
-
过于复杂的命令:如果命令执行逻辑非常复杂,可能会导致命令对象的实现变得难以维护。
核心要素
-
Command(命令接口):定义命令的接口,通常包含
execute()
和undo()
方法。 -
ConcreteCommand(具体命令):实现命令接口的类,负责调用接收者的相应方法来执行操作。
-
Receiver(接收者):实际执行命令请求的对象。
-
Invoker(调用者):负责调用命令对象的
execute()
方法来执行命令。 -
Client(客户端):创建具体命令对象并将接收者与命令对象关联。
Java代码完整示例
示例:简单的命令模式实现
// 命令接口
interface Command {
void execute();
void undo(); // 撤销方法
}
// 接收者类
class Light {
public void turnOn() {
System.out.println("The light is on.");
}
public void turnOff() {
System.out.println("The light is off.");
}
}
// 具体命令类:打开灯
class TurnOnLightCommand implements Command {
private Light light;
public TurnOnLightCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOn();
}
@Override
public void undo() {
light.turnOff();
}
}
// 具体命令类:关闭灯
class TurnOffLightCommand implements Command {
private Light light;
public TurnOffLightCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOff();
}
@Override
public void undo() {
light.turnOn();
}
}
// 调用者类
class RemoteControl {
private Command command;
private Command lastCommand; // 记录上一个命令
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
lastCommand = command; // 记录当前命令
}
public void pressUndo() {
if (lastCommand != null) {
lastCommand.undo(); // 撤销上一个命令
}
}
}
// 客户端代码
public class CommandPatternDemo {
public static void main(String[] args) {
Light livingRoomLight = new Light();
// 创建命令对象
Command turnOn = new TurnOnLightCommand(livingRoomLight);
Command turnOff = new TurnOffLightCommand(livingRoomLight);
// 设置命令到调用者
RemoteControl remote = new RemoteControl();
// 打开灯
remote.setCommand(turnOn);
remote.pressButton();
// 撤销:关闭灯
remote.pressUndo();
// 关闭灯
remote.setCommand(turnOff);
remote.pressButton();
// 撤销:打开灯
remote.pressUndo();
}
}
输出结果:
The light is on.
The light is off.
The light is off.
The light is on.
各种变形用法完整示例
-
支持撤销操作的命令模式
通过在命令接口中添加
undo()
方法,您可以轻松支持命令的撤销功能。代码示例:支持撤销的命令模式
// 上面的代码示例已包含撤销功能,您可以直接使用。
-
宏命令模式
宏命令允许将多个命令打包为一个命令对象,以便一次性执行。
代码示例:宏命令
import java.util.ArrayList; import java.util.List; // 宏命令类 class MacroCommand implements Command { private List<Command> commands = new ArrayList<>(); public void addCommand(Command command) { commands.add(command); } @Override public void execute() { for (Command command : commands) { command.execute(); } } @Override public void undo() { for (Command command : commands) { command.undo(); } } } public class MacroCommandDemo { public static void main(String[] args) { Light livingRoomLight = new Light(); Command turnOn = new TurnOnLightCommand(livingRoomLight); Command turnOff = new TurnOffLightCommand(livingRoomLight); MacroCommand macroCommand = new MacroCommand(); macroCommand.addCommand(turnOn); macroCommand.addCommand(turnOff); // 执行宏命令 RemoteControl remote = new RemoteControl(); remote.setCommand(macroCommand); remote.pressButton(); // 执行所有命令 } }
-
命令队列
在异步执行或延迟执行场景中,可以将命令存储在队列中。
代码示例:命令队列
import java.util.LinkedList; import java.util.Queue; class CommandQueue { private Queue<Command> commandQueue = new LinkedList<>(); public void addCommand(Command command) { commandQueue.offer(command); } public void executeAll() { while (!commandQueue.isEmpty()) { Command command = commandQueue.poll(); command.execute(); } } } public class CommandQueueDemo { public static void main(String[] args) { CommandQueue commandQueue = new CommandQueue(); Light livingRoomLight = new Light(); commandQueue.addCommand(new TurnOnLightCommand(livingRoomLight)); commandQueue.addCommand(new TurnOffLightCommand(livingRoomLight)); // 执行命令队列中的所有命令 commandQueue.executeAll(); } }
通过这些示例,命令模式的灵活性和强大功能得以体现,可以根据具体需求实现多种变形用法。