Skip to content
LLD Learn/Behavioral Patterns
Browsing as a guest. Sign in to save your progress and earn XP as you complete chapters.

Command: Undo/Redo & Queued Actions

7 min read

You'll learn to

  • -Encapsulate a request as an object so it can be queued, logged, or undone
  • -Implement an undo/redo stack using Command, the way a text editor or remote-control interview question expects

Command encapsulates a request as an object, letting you parameterize callers with different requests, queue or log requests, and support undoable operations. The core move is turning "do this action" from a direct method call into an object that can be stored, passed around, and executed later - or reversed.

The Core Mechanic

A request as an object, with its own execute() and undo()
class Command(ABC):
    @abstractmethod
    def execute(self) -> None: ...
    @abstractmethod
    def undo(self) -> None: ...

class TextDocument:
    def __init__(self):
        self.content = ""

class InsertTextCommand(Command):
    def __init__(self, document: TextDocument, text: str):
        self._document = document
        self._text = text

    def execute(self) -> None:
        self._document.content += self._text

    def undo(self) -> None:
        self._document.content = self._document.content[:-len(self._text)]

class CommandHistory:                          # the undo/redo stack
    def __init__(self):
        self._history: list[Command] = []

    def execute(self, command: Command) -> None:
        command.execute()
        self._history.append(command)

    def undo_last(self) -> None:
        if self._history:
            self._history.pop().undo()

Why This Is the Standard Undo/Redo Shape

The reason Command specifically (rather than just calling document.insert(text) directly) enables undo/redo is that the command object retains everything needed to reverse itself - the exact text inserted, in this case - at the moment it was created. A plain method call has no memory of what happened; a Command object does, which is exactly what a history stack needs to pop and reverse operations in order.

The Remote Control / Queued-Actions Framing

The other classic framing for this pattern is a universal remote control: each button is bound to a Command object (LightOnCommand, TVOnCommand), and the remote's press_button() method just calls execute() on whatever command is currently bound - the remote never needs to know what a "light" or a "TV" actually does. This same shape - decoupling "trigger the action" from "know how to perform the action" - is what makes Command useful for job queues and macro/batch operations too: a queue of Command objects can be built up, persisted, and executed later, in order, by a worker that never needs to know what any individual command does.

Command and Strategy look similar (both wrap behavior behind an interface), but Command specifically models a request with a history/undo/queuing concern, while Strategy models an interchangeable algorithm with no notion of "undo" or "when it ran."

Interview Signal is part of Pro

See a real weak answer next to a real strong one for this exact topic.

Quiz is part of Pro

Test what you just read with a short quiz, and bank the XP.

ScaleDojo Logo
Initializing ScaleDojo