Skip to main content

Command Pattern in JavaScript (Live Playground)

The Command pattern is a behavioral design pattern that turns a request into a stand-alone object containing all the information required to perform the request. This pattern enables you to decouple the sender of a request from the object that carries out the request. In this tutorial, we'll explore the Command pattern in JavaScript, including its use cases, implementation, and benefits.

Why Use the Command Pattern?

The Command pattern is useful when you want to:

  1. Decouple the sender of a request from the receiver by using a stand-alone command object.
  2. Implement undo and redo functionality by storing command objects in a history list.
  3. Create a flexible and maintainable architecture that can be easily extended with new commands.

Implementing the Command Pattern in JavaScript

Here's an example of how to implement the Command pattern using JavaScript classes:

TypeScript
// Command interface
class Command {
execute() {}
undo() {}
}

// Concrete commands
class AddCommand extends Command {
constructor(receiver, value) {
super();
this.receiver = receiver;
this.value = value;
}

execute() {
this.receiver.add(this.value);
}

undo() {
this.receiver.subtract(this.value);
}
}

class SubtractCommand extends Command {
constructor(receiver, value) {
super();
this.receiver = receiver;
this.value = value;
}

execute() {
this.receiver.subtract(this.value);
}

undo() {
this.receiver.add(this.value);
}
}

// Receiver
class Calculator {
constructor() {
this.total = 0;
}

add(value) {
this.total += value;
}

subtract(value) {
this.total -= value;
}

getTotal() {
return this.total;
}
}

// Invoker
class CommandInvoker {
constructor() {
this.commands = [];
this.current = -1;
}

executeCommand(command) {
this.current++;
this.commands[this.current] = command;
command.execute();
}

undo() {
if (this.current >= 0) {
this.commands[this.current].undo();
this.current--;
}
}
}

// Client code
const calculator = new Calculator();
const invoker = new CommandInvoker();

const addCommand = new AddCommand(calculator, 5);
const subtractCommand = new SubtractCommand(calculator, 2);

invoker.executeCommand(addCommand);
invoker.executeCommand(subtractCommand);

console.log(calculator.getTotal()); // Output: 3

invoker.undo();
console.log(calculator.getTotal()); // Output: 5

In this example, the Command class represents the command interface, and AddCommand and SubtractCommand are concrete command classes. The Calculator class represents the receiver, and the CommandInvoker class manages the execution and undoing of commands.

Live Playground, Try it Yourself

Benefits of the Command Pattern

Implementing the Command pattern in your JavaScript projects offers several benefits:

  1. Decoupling: The Command pattern decouples the sender of a request from the receiver, promoting a more flexible and maintainable architecture.
  2. Extensibility: The Command pattern makes it easy to add new commands without modifying the existing code, promoting the Open/Closed Principle.
  3. Undo/Redo Functionality: The Command pattern enables you to implement undo and redo functionality by storing executed command objects in a history list, allowing you to easily revert or reapply changes.
  4. Better Organization: The Command pattern helps you to organize your code by encapsulating each action in a separate command object, improving code readability and maintainability.

Conclusion

In summary, the Command pattern is a valuable tool in JavaScript development that can help you create flexible, maintainable code. By understanding and implementing this pattern, you can enhance your web development skills and create more robust applications.