Bird
Raised Fist0
LLDsystem_design~7 mins

Command pattern in LLD - System Design Guide

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Problem Statement
When a system tightly couples the object that sends a request to the object that performs it, it becomes hard to extend, queue, or undo operations. This rigidity leads to code that is difficult to maintain and evolve, especially when new commands or complex workflows are needed.
Solution
The Command pattern encapsulates a request as an object, separating the sender from the receiver. This allows commands to be parameterized, queued, logged, or undone independently of the sender, enabling flexible and extensible command management.
Architecture
Client
(Invoker)
Command
ConcreteCommand

This diagram shows the Client (Invoker) sending requests to Command objects, which encapsulate actions executed by the Receiver. The ConcreteCommand implements the Command interface and calls the Receiver's methods.

Trade-offs
✓ Pros
Decouples the sender and receiver, enabling flexible command management.
Supports undo/redo operations by storing command history.
Allows queuing, logging, and scheduling of commands easily.
Facilitates adding new commands without changing existing code.
✗ Cons
Increases the number of classes and objects, adding complexity.
May introduce overhead due to additional layers of abstraction.
Requires careful design to manage command lifecycle and state.
Use when you need to parameterize objects with operations, support undo/redo, queue or log requests, or decouple request senders from receivers, especially in GUI applications or transactional systems.
Avoid when the system has very simple operations with no need for extensibility, undo, or queuing, as the added abstraction may be unnecessary overhead.
Real World Examples
Amazon
Uses the Command pattern in their order processing system to encapsulate order actions, enabling retries, cancellations, and audit logging.
Microsoft
Implements the Command pattern in Office applications to support undo/redo functionality for user actions.
Uber
Applies the Command pattern to manage ride requests and cancellations, allowing flexible command scheduling and retries.
Code Example
The before code tightly couples the Switch to the Light's methods. The after code uses the Command pattern to encapsulate requests as objects, allowing the Switch to execute commands without knowing the details of the Light. This decouples sender and receiver and enables flexible command management.
LLD
### Before (without Command pattern):
class Light:
    def turn_on(self):
        print("Light is ON")
    def turn_off(self):
        print("Light is OFF")

class Switch:
    def __init__(self, light):
        self.light = light
    def on(self):
        self.light.turn_on()
    def off(self):
        self.light.turn_off()

light = Light()
switch = Switch(light)
switch.on()
switch.off()

### After (with Command pattern):
from abc import ABC, abstractmethod

class Command(ABC):
    @abstractmethod
    def execute(self):
        pass

class Light:
    def turn_on(self):
        print("Light is ON")
    def turn_off(self):
        print("Light is OFF")

class TurnOnCommand(Command):
    def __init__(self, light):
        self.light = light
    def execute(self):
        self.light.turn_on()

class TurnOffCommand(Command):
    def __init__(self, light):
        self.light = light
    def execute(self):
        self.light.turn_off()

class Switch:
    def __init__(self, on_command, off_command):
        self.on_command = on_command
        self.off_command = off_command
    def on(self):
        self.on_command.execute()
    def off(self):
        self.off_command.execute()

light = Light()
on_command = TurnOnCommand(light)
off_command = TurnOffCommand(light)
switch = Switch(on_command, off_command)
switch.on()
switch.off()
OutputSuccess
Alternatives
Strategy pattern
Encapsulates interchangeable algorithms but does not encapsulate requests as objects for queuing or undo.
Use when: Choose when you need to select algorithms dynamically but do not require command queuing or undo functionality.
Mediator pattern
Centralizes communication between objects rather than encapsulating requests as objects.
Use when: Choose when you want to reduce direct dependencies between objects but do not need command encapsulation.
Summary
The Command pattern encapsulates requests as objects to decouple senders from receivers.
It enables flexible command management such as queuing, undo, and logging.
This pattern improves extensibility but adds abstraction and complexity.

Practice

(1/5)
1. What is the main purpose of the Command pattern in system design?
easy
A. To create multiple instances of a class efficiently
B. To ensure only one instance of a class exists
C. To define a family of algorithms and make them interchangeable
D. To encapsulate a request as an object, allowing parameterization and queuing of requests

Solution

  1. Step 1: Understand the Command pattern role

    The Command pattern encapsulates a request as an object, which allows you to parameterize clients with queues, requests, and operations.
  2. Step 2: Compare with other patterns

    Creating multiple instances relates to Prototype or Factory, a family of algorithms to Strategy, and a single instance to Singleton; these are not Command.
  3. Final Answer:

    To encapsulate a request as an object, allowing parameterization and queuing of requests -> Option D
  4. Quick Check:

    Command pattern = encapsulate request [OK]
Hint: Command pattern = wrap action as object for flexibility [OK]
Common Mistakes:
  • Confusing Command with Singleton or Factory patterns
  • Thinking Command creates instances instead of encapsulating actions
  • Mixing Command with Strategy pattern
2. Which of the following is the correct method signature for the execute method in a Command interface?
easy
A. void execute(String[] args);
B. void execute();
C. boolean execute(String commandName);
D. int execute(int commandId);

Solution

  1. Step 1: Recall Command interface basics

    The Command interface typically defines a simple execute() method without parameters to perform the action.
  2. Step 2: Analyze options

    The options with parameters (String[], int commandId, String commandName) or return types are not standard in Command pattern interfaces; the command object itself holds necessary data.
  3. Final Answer:

    void execute(); -> Option B
  4. Quick Check:

    Command execute method = void execute() [OK]
Hint: Command execute usually has no parameters [OK]
Common Mistakes:
  • Adding parameters to execute method unnecessarily
  • Confusing Command with other patterns that require arguments
  • Assuming execute returns a value
3. Given the following code snippet implementing the Command pattern, what will be the output?
class Light {
  turnOn() { console.log('Light is ON'); }
  turnOff() { console.log('Light is OFF'); }
}

class TurnOnCommand {
  constructor(light) { this.light = light; }
  execute() { this.light.turnOn(); }
}

class TurnOffCommand {
  constructor(light) { this.light = light; }
  execute() { this.light.turnOff(); }
}

class RemoteControl {
  setCommand(command) { this.command = command; }
  pressButton() { this.command.execute(); }
}

const light = new Light();
const remote = new RemoteControl();
remote.setCommand(new TurnOnCommand(light));
remote.pressButton();
remote.setCommand(new TurnOffCommand(light));
remote.pressButton();
medium
A. Light is ON\nLight is OFF
B. Light is OFF\nLight is ON
C. Light is ON\nLight is ON
D. Light is OFF\nLight is OFF

Solution

  1. Step 1: Trace first command execution

    The remote sets the command to TurnOnCommand and calls execute, which calls light.turnOn(), printing 'Light is ON'.
  2. Step 2: Trace second command execution

    The remote sets the command to TurnOffCommand and calls execute, which calls light.turnOff(), printing 'Light is OFF'.
  3. Final Answer:

    Light is ON\nLight is OFF -> Option A
  4. Quick Check:

    TurnOn then TurnOff commands print ON then OFF [OK]
Hint: Follow command set and execute calls step-by-step [OK]
Common Mistakes:
  • Mixing order of commands
  • Assuming commands execute immediately without setting
  • Confusing method names turnOn and turnOff
4. In the following code, what is the main issue that prevents the Command pattern from working correctly?
class Light {
  turnOn() { console.log('Light is ON'); }
}

class TurnOnCommand {
  constructor() { }
  execute() { this.light.turnOn(); }
}

const light = new Light();
const command = new TurnOnCommand();
command.execute();
medium
A. The execute method should return a value
B. The Light class is missing the turnOff method
C. The TurnOnCommand constructor does not receive or store the Light object
D. The command object is not instantiated properly

Solution

  1. Step 1: Check TurnOnCommand constructor

    The constructor does not accept or assign the Light object to this.light, so this.light is undefined.
  2. Step 2: Analyze execute method call

    Calling this.light.turnOn() fails because this.light is undefined, causing an error.
  3. Final Answer:

    The TurnOnCommand constructor does not receive or store the Light object -> Option C
  4. Quick Check:

    Missing light reference in command = error [OK]
Hint: Ensure command stores receiver object before execute [OK]
Common Mistakes:
  • Ignoring missing receiver object in command
  • Thinking missing turnOff method causes error here
  • Assuming execute must return a value
5. You are designing a text editor with undo functionality using the Command pattern. Which design choice best supports undo operations efficiently?
hard
A. Store a history stack of Command objects and call an undo() method on the last command
B. Keep a log of all text changes as strings and replay them to undo
C. Use a single Command object that modifies text directly without history
D. Implement undo by reloading the entire document from disk

Solution

  1. Step 1: Understand undo with Command pattern

    Each Command object should implement both execute() and undo() methods to reverse its action.
  2. Step 2: Evaluate design choices

    Storing a history stack of Command objects allows calling undo() on the last command efficiently. Other options either lack command encapsulation or are inefficient.
  3. Final Answer:

    Store a history stack of Command objects and call an undo() method on the last command -> Option A
  4. Quick Check:

    Undo = command history stack with undo() [OK]
Hint: Undo needs command history with undo method [OK]
Common Mistakes:
  • Using string logs instead of command objects
  • Not implementing undo in commands
  • Reloading entire document is inefficient