The Command Pattern encapsulates a request as an object, enabling you to parameterize methods with different requests, delay their execution, queue or log them, and support undoable operations.
- Decoupling: Separates sender and receiver of commands.
- Flexibility: Easily support operations like undo, redo, and command logging.
- Extensibility: Introduce new commands without changing existing code.
- You need commands executed later or queued.
- You require an undo/redo functionality.
- You want to decouple the invoker from the receiver.
interface Command {
execute(): void;
undo(): void;
}
class Light {
private isOn = false;
turnOn(): void {
this.isOn = true;
console.log("The light is on");
}
turnOff(): void {
this.isOn = false;
console.log("The light is off");
}
}
class LightOnCommand implements Command {
private light: Light;
constructor(light: Light) {
this.light = light;
}
execute(): void {
this.light.turnOn();
}
undo(): void {
this.light.turnOff();
}
}
class LightOffCommand implements Command {
private light: Light;
constructor(light: Light) {
this.light = light;
}
execute(): void {
this.light.turnOff();
}
undo(): void {
this.light.turnOn();
}
}
class RemoteControl {
private history: Command[] = [];
executeCommand(command: Command): void {
command.execute();
this.history.push(command);
}
undo(): void {
const command = this.history.pop();
if (command) {
command.undo();
}
}
}
const light = new Light();
const remoteControl = new RemoteControl();
const lightOn = new LightOnCommand(light);
const lightOff = new LightOffCommand(light);
remoteControl.executeCommand(lightOn); // Output: The light is on
remoteControl.executeCommand(lightOff); // Output: The light is off
remoteControl.undo(); // Output: The light is on
remoteControl.undo(); // Output: The light is off
The Command Pattern effectively encapsulates operations as objects, allowing greater flexibility, decoupling, and easy management of actions such as undo and redo.