Command: Undo/Redo & Queued Actions
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
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.