Java命令模式详解
命令模式详解
一、命令模式概述
命令模式(Command Pattern)是一种行为型设计模式,它将请求封装为对象,从而允许使用不同的请求参数化其他对象,并支持请求的排队、记录、撤销等操作。
核心特点
- 解耦调用者与执行者:调用者无需知道具体执行细节
- 参数化请求:可将命令对象作为参数传递
- 支持撤销/重做:记录命令历史实现操作回滚
- 支持事务:实现命令的原子执行
二、命令模式的结构
主要角色
- Command:抽象命令接口
- ConcreteCommand:具体命令实现
- Invoker:调用者/请求者
- Receiver:命令接收者/执行者
- Client:创建具体命令并设置接收者
三、命令模式的实现
1. 基本实现
// 命令接口
public interface Command {
void execute();
void undo();
}
// 接收者 - 知道如何执行操作
public class Light {
public void on() {
System.out.println("开灯");
}
public void off() {
System.out.println("关灯");
}
}
// 具体命令 - 开灯命令
public class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
public void execute() {
light.on();
}
public void undo() {
light.off();
}
}
// 调用者 - 遥控器
public class RemoteControl {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
}
public void pressUndo() {
command.undo();
}
}
// 使用示例
Light light = new Light();
Command lightOn = new LightOnCommand(light);
RemoteControl remote = new RemoteControl();
remote.setCommand(lightOn);
remote.pressButton(); // 开灯
remote.pressUndo(); // 关灯
2. 支持多命令和撤销历史
// 高级遥控器
public class AdvancedRemoteControl {
private List<Command> commandHistory = new ArrayList<>();
public void executeCommand(Command command) {
command.execute();
commandHistory.add(command);
}
public void undoLastCommand() {
if (!commandHistory.isEmpty()) {
Command lastCommand = commandHistory.remove(commandHistory.size() - 1);
lastCommand.undo();
}
}
}
四、命令模式的应用场景
1. 文本编辑器操作
// 文档类 - 接收者
public class Document {
private StringBuilder content = new StringBuilder();
public void write(String text) {
content.append(text);
}
public void delete(int length) {
if (content.length() >= length) {
content.delete(content.length() - length, content.length());
}
}
public String getContent() {
return content.toString();
}
}
// 抽象命令
public interface TextCommand {
void execute();
void undo();
}
// 写入命令
public class WriteCommand implements TextCommand {
private Document document;
private String text;
public WriteCommand(Document document, String text) {
this.document = document;
this.text = text;
}
public void execute() {
document.write(text);
}
public void undo() {
document.delete(text.length());
}
}
// 编辑器 - 调用者
public class TextEditor {
private List<TextCommand> history = new ArrayList<>();
private Document document = new Document();
public void executeCommand(TextCommand command) {
command.execute();
history.add(command);
}
public void undo() {
if (!history.isEmpty()) {
TextCommand lastCommand = history.remove(history.size() - 1);
lastCommand.undo();
}
}
public void showDocument() {
System.out.println("当前文档内容: " + document.getContent());
}
}
2. 交易系统
// 交易接收者
public class StockTrade {
public void buy(String stock, int shares) {
System.out.println("买入 " + shares + " 股 " + stock);
}
public void sell(String stock, int shares) {
System.out.println("卖出 " + shares + " 股 " + stock);
}
}
// 订单命令接口
public interface Order {
void execute();
}
// 买入命令
public class BuyOrder implements Order {
private StockTrade stockTrade;
private String stock;
private int shares;
public BuyOrder(StockTrade stockTrade, String stock, int shares) {
this.stockTrade = stockTrade;
this.stock = stock;
this.shares = shares;
}
public void execute() {
stockTrade.buy(stock, shares);
}
}
// 订单处理器 - 调用者
public class OrderProcessor {
private List<Order> orders = new ArrayList<>();
public void takeOrder(Order order) {
orders.add(order);
}
public void processOrders() {
for (Order order : orders) {
order.execute();
}
orders.clear();
}
}
3. 智能家居控制
// 设备接口
public interface SmartDevice {
void on();
void off();
}
// 具体设备
public class SmartLight implements SmartDevice {
public void on() {
System.out.println("智能灯开启");
}
public void off() {
System.out.println("智能灯关闭");
}
}
// 场景命令
public class SceneCommand implements Command {
private List<Command> commands = new ArrayList<>();
public void addCommand(Command command) {
commands.add(command);
}
public void execute() {
for (Command command : commands) {
command.execute();
}
}
public void undo() {
for (int i = commands.size() - 1; i >= 0; i--) {
commands.get(i).undo();
}
}
}
// 使用场景命令
SceneCommand goodNightScene = new SceneCommand();
goodNightScene.addCommand(new LightOffCommand(livingRoomLight));
goodNightScene.addCommand(new ThermostatSetCommand(thermostat, 20));
remote.setCommand(goodNightScene);
remote.pressButton(); // 执行晚安场景
五、命令模式的变体
1. 宏命令(组合命令)
public class MacroCommand implements Command {
private Command[] commands;
public MacroCommand(Command[] commands) {
this.commands = commands;
}
public void execute() {
for (Command command : commands) {
command.execute();
}
}
public void undo() {
for (int i = commands.length - 1; i >= 0; i--) {
commands[i].undo();
}
}
}
2. 延迟执行命令
public class DelayedCommand implements Command {
private Command command;
private long delayMillis;
public DelayedCommand(Command command, long delayMillis) {
this.command = command;
this.delayMillis = delayMillis;
}
public void execute() {
new Thread(() -> {
try {
Thread.sleep(delayMillis);
command.execute();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
}
}
六、命令模式的优缺点
优点
- 解耦调用者与执行者:降低系统耦合度
- 易于扩展:新增命令不影响现有代码
- 支持撤销/重做:可维护命令历史
- 支持事务:可实现命令的原子执行
- 灵活组合:可组合多个命令形成宏命令
缺点
- 类数量增加:每个命令都需要一个具体类
- 复杂度增加:对简单操作可能过度设计
- 性能开销:命令对象创建和管理需要额外资源
七、最佳实践
- 合理设计命令粒度:避免命令过于简单或复杂
- 考虑线程安全:多线程环境下的命令执行
- 限制命令历史:避免撤销历史占用过多内存
- 使用对象池:对频繁创建的命令对象使用对象池
- 结合备忘录模式:增强撤销功能的灵活性
八、总结
命令模式是封装操作请求的强大工具,特别适用于:
- 需要将请求调用者与执行者解耦的场景
- 需要支持撤销/重做功能的系统
- 需要实现事务或原子操作的场景
- 需要排队或延迟执行请求的场景
在实际开发中,命令模式常见于:
- GUI事件处理(如按钮点击)
- 事务系统
- 宏录制功能
- 任务调度系统
- 智能家居控制
正确使用命令模式可以提高系统的灵活性和可扩展性,但需要注意不要过度使用,对于简单操作直接调用可能更合适。