命令模式是一种行为设计模式,它将一个请求封装成一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。
// 命令接口
class Command {
execute() {
throw new Error('Method not implemented');
}
undo() {
throw new Error('Method not implemented');
}
}
// 接收者类:灯
class Light {
#isOn = false;
#brightness = 0;
turnOn() {
this.#isOn = true;
console.log("Light is turned on");
}
turnOff() {
this.#isOn = false;
console.log("Light is turned off");
}
setBrightness(level) {
this.#brightness = level;
console.log(`Light brightness set to ${level}%`);
}
get status() {
return `Light is ${this.#isOn ? 'on' : 'off'}, brightness: ${this.#brightness}%`;
}
}
// 具体命令:开灯
class LightOnCommand extends Command {
#light;
constructor(light) {
super();
this.#light = light;
}
execute() {
this.#light.turnOn();
}
undo() {
this.#light.turnOff();
}
}
// 具体命令:关灯
class LightOffCommand extends Command {
#light;
constructor(light) {
super();
this.#light = light;
}
execute() {
this.#light.turnOff();
}
undo() {
this.#light.turnOn();
}
}
// 具体命令:调节亮度
class DimLightCommand extends Command {
#light;
#prevBrightness;
#targetBrightness;
constructor(light, brightness) {
super();
this.#light = light;
this.#targetBrightness = brightness;
}
execute() {
this.#prevBrightness = this.#light.status.match(/brightness: (\d+)%/)[1];
this.#light.setBrightness(this.#targetBrightness);
}
undo() {
this.#light.setBrightness(this.#prevBrightness);
}
}
// 调用者:遥控器
class RemoteControl {
#commands = new Map();
#history = [];
setCommand(buttonName, command) {
this.#commands.set(buttonName, command);
}
pressButton(buttonName) {
const command = this.#commands.get(buttonName);
if (command) {
command.execute();
this.#history.push(command);
} else {
console.log(`Button ${buttonName} is not programmed`);
}
}
undoLastCommand() {
const command = this.#history.pop();
if (command) {
command.undo();
} else {
console.log("No commands to undo");
}
}
}
// 客户端代码
function clientCode() {
const livingRoomLight = new Light();
const remoteControl = new RemoteControl();
remoteControl.setCommand("on", new LightOnCommand(livingRoomLight));
remoteControl.setCommand("off", new LightOffCommand(livingRoomLight));
remoteControl.setCommand("dim", new DimLightCommand(livingRoomLight, 50));
console.log("Pressing 'on' button:");
remoteControl.pressButton("on");
console.log(livingRoomLight.status);
console.log("\nPressing 'dim' button:");
remoteControl.pressButton("dim");
console.log(livingRoomLight.status);
console.log("\nPressing 'off' button:");
remoteControl.pressButton("off");
console.log(livingRoomLight.status);
console.log("\nUndoing last command:");
remoteControl.undoLastCommand();
console.log(livingRoomLight.status);
console.log("\nUndoing another command:");
remoteControl.undoLastCommand();
console.log(livingRoomLight.status);
}
clientCode();
实现思路
-
Command接口:定义了所有具体命令必须实现的execute和undo方法。 -
Light类(接收者):- 实现了灯的基本功能,如开关和调节亮度。
- 使用私有字段
#isOn和#brightness来存储灯的状态。
-
具体命令类(
LightOnCommand,LightOffCommand,DimLightCommand):- 每个类封装了一个特定的操作。
- 持有对接收者(Light)的引用。
- 实现了
execute和undo方法。
-
RemoteControl类(调用者):- 使用
Map来存储按钮和对应的命令。 - 维护一个命令历史,用于实现撤销功能。
- 提供了设置命令、执行命令和撤销命令的方法。
- 使用
优点
- 解耦:将请求的发送者和接收者解耦。
- 扩展性:可以轻松添加新的命令,而不需要修改现有代码。
- 组合:可以将简单命令组合成复杂的命令。
- 撤销/重做:通过维护历史记录,可以实现撤销和重做功能。
- 延迟执行:命令可以被存储和调度,以便稍后执行。