The Command Design Pattern is used to encapsulate a request as an object, thereby decoupling the sender of the request from its receiver. This enables flexible command management such as queuing, logging, undo/redo, and dynamic command execution.

Real-World Analogy:

Todo: it involves strategy pattern?

Components

SOLID principles

Implementation

Composition + Interface Polymorphism

// Receiver
class Light {
  turnOn() {
    console.log("Light is ON");
  }

  turnOff() {
    console.log("Light is OFF");
  }
}

// Command
interface Command {
  execute(): void;
}

// Concrete Commands
class TurnOnLightCommand implements Command {
  constructor(private light: Light) {}
  execute(): void {
    this.light.turnOn();
  }
}

class TurnOffLightCommand implements Command {
  constructor(private light: Light) {}
  execute(): void {
    this.light.turnOff();
  }
}

// Invoker
class RemoteControl {
  private command: Command;

  setCommand(command: Command) {
    this.command = command;
  }

  pressButton() {
    this.command.execute();
  }
}

// Client
const light = new Light();
const onCommand = new TurnOnLightCommand(light);
const offCommand = new TurnOffLightCommand(light);

const remote = new RemoteControl();
remote.setCommand(onCommand);
remote.pressButton(); // Light is ON
remote.setCommand(offCommand);
remote.pressButton(); // Light is OFF

Go Composition + Interface Polymorphism

// Receiver
type Light struct{}

func (l *Light) TurnOn() {
	fmt.Println("Light is ON")
}

func (l *Light) TurnOff() {
	fmt.Println("Light is OFF")
}

// Commands
type Command interface {
	Execute()
}

type TurnOnLightCommand struct {
	light *Light
}
func (c *TurnOnLightCommand) Execute() {
	c.light.TurnOn()
}

type TurnOffLightCommand struct {
	light *Light
}
func (c *TurnOffLightCommand) Execute() {
	c.light.TurnOff()
}

// Invoker
type RemoteControl struct {
	command Command
}

func (r *RemoteControl) SetCommand(command Command) {
	r.command = command
}

func (r *RemoteControl) PressButton() {
	r.command.Execute()
}

// Client
light := &Light{}
onCommand := &TurnOnLightCommand{light}
offCommand := &TurnOffLightCommand{light}

remote := &RemoteControl{}
remote.SetCommand(onCommand)
remote.PressButton() // Light is ON

remote.SetCommand(offCommand)
remote.PressButton() // Light is OFF

References