What is the Command pattern and how is it used?
Topics
JAVASCRIPT
Edit on GitHub
TL;DR
The Command pattern is a behavioral design pattern that turns a request into a stand-alone object containing all information about the request. This transformation allows for parameterization of methods with different requests, queuing of requests, and logging of the requests. It also supports undoable operations. In JavaScript, it can be implemented by creating command objects with execute
and undo
methods.
class Command {execute() {}undo() {}}class LightOnCommand extends Command {constructor(light) {super();this.light = light;}execute() {this.light.on();}undo() {this.light.off();}}class Light {on() {console.log('Light is on');}off() {console.log('Light is off');}}const light = new Light();const lightOnCommand = new LightOnCommand(light);lightOnCommand.execute(); // Light is onlightOnCommand.undo(); // Light is off
What is the Command pattern and how is it used?
Definition
The Command pattern is a behavioral design pattern that encapsulates a request as an object, thereby allowing for the parameterization of clients with queues, requests, and operations. It also provides support for undoable operations.
Components
- Command: Declares an interface for executing an operation.
- ConcreteCommand: Implements the
execute
method by invoking the corresponding operation(s) onReceiver
. - Receiver: Knows how to perform the operations associated with carrying out a request.
- Invoker: Asks the command to carry out the request.
- Client: Creates a
ConcreteCommand
object and sets its receiver.
Implementation in JavaScript
Step 1: Define the Command interface
class Command {execute() {}undo() {}}
Step 2: Create ConcreteCommand classes
class LightOnCommand extends Command {constructor(light) {super();this.light = light;}execute() {this.light.on();}undo() {this.light.off();}}class LightOffCommand extends Command {constructor(light) {super();this.light = light;}execute() {this.light.off();}undo() {this.light.on();}}
Step 3: Define the Receiver
class Light {on() {console.log('Light is on');}off() {console.log('Light is off');}}
Step 4: Create the Invoker
class RemoteControl {setCommand(command) {this.command = command;}pressButton() {this.command.execute();}pressUndo() {this.command.undo();}}
Step 5: Client code
const light = new Light();const lightOnCommand = new LightOnCommand(light);const lightOffCommand = new LightOffCommand(light);const remote = new RemoteControl();remote.setCommand(lightOnCommand);remote.pressButton(); // Light is onremote.pressUndo(); // Light is offremote.setCommand(lightOffCommand);remote.pressButton(); // Light is offremote.pressUndo(); // Light is on
Use cases
- Undo/Redo functionality: The Command pattern is ideal for implementing undo and redo operations.
- Macro commands: It can be used to implement a sequence of commands.
- Logging changes: It helps in logging changes and auditing them later.
- GUI buttons and menu items: It is useful for implementing actions triggered by GUI elements.