Skip to main content

命令模式 (Command)

场景问题​

问题案例​

考虑一个遥控器控制家电的场景,用户可以对灯、电视等设备进行开关操作,并且希望支持操作的撤销和记录。

不用模式的解决方案​

实现简化版本​

最直接的做法是遥控器直接调用家电的方法:

public class Light {
public void on() { System.out.println("灯打开"); }
public void off() { System.out.println("灯关闭"); }
}
public class RemoteControl {
private Light light;
public RemoteControl(Light light) { this.light = light; }
public void pressOn() { light.on(); }
public void pressOff() { light.off(); }
}

使用示例​

Light light = new Light();
RemoteControl remote = new RemoteControl(light);
remote.pressOn();
remote.pressOff();

有何问题​

  1. 遥控器与具体家电耦合,扩展性差。
  2. 难以支持操作记录、撤销等功能。
  3. 新增设备需修改遥控器代码。

解决方案​

命令模式的定义​

将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录日志,以及支持可撤销的操作。

应用命令模式的思路​

  • 定义命令接口,具体命令实现该接口。
  • 命令对象持有接收者引用,调用接收者方法。
  • 调用者持有命令对象,触发命令执行。

命令模式的结构​

  • Command:命令接口,定义执行方法。
  • ConcreteCommand:具体命令,实现命令逻辑。
  • Invoker:调用者,持有命令对象。
  • Receiver:接收者,执行实际操作。

命令模式的实现​

// 命令接口
public interface Command {
void execute();
}

// 接收者
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 class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light) { this.light = light; }
public void execute() { light.off(); }
}

// 调用者
public class RemoteControl {
private Command command;
public void setCommand(Command command) { this.command = command; }
public void pressButton() { command.execute(); }
}

使用示例​

public class Client {
public static void main(String[] args) {
Light light = new Light();
Command on = new LightOnCommand(light);
Command off = new LightOffCommand(light);
RemoteControl remote = new RemoteControl();
remote.setCommand(on);
remote.pressButton();
remote.setCommand(off);
remote.pressButton();
}
}

命令重写示例​

示例结构​


示例代码​

见上文"命令模式的实现"部分。


模式讲解​

命令模式的功能​

  • 解耦请求发送者和接收者。
  • 支持操作记录、撤销、排队等功能。
  • 扩展新命令灵活。

实现成接口​

  • 命令接口通常定义为接口或抽象类。

使用工厂方法​

  • 可结合工厂方法模式,统一创建命令对象。

切换产品簇​

  • 可用于切换不同的命令族,如不同家电命令。

执行时序图​