Command Pattern Implementor
by @quochungto
Implement the Command pattern to encapsulate requests as objects, enabling parameterized operations, queuing, logging, and undo/redo. Use when you need to de...
Example 1: Document Editor with Multi-Level Undo
Scenario: A text editor with menus for Cut, Copy, Paste, and Bold. Users expect unlimited undo/redo accessible from Edit > Undo and Edit > Redo, and from Ctrl+Z / Ctrl+Y. The same Cut command should be triggerable from the menu, the toolbar, and the keyboard shortcut.
Trigger: "We need multi-level undo for edit operations and the same command needs to work from three different places in the UI."
Process:
history.Undo(). Edit > Redo calls history.Redo().CutCommand(document), assigns it to the menu item, toolbar button, and keyboard handler. All three share the same instance.Output:
CutCommand.Execute() saves selected text to clipboard, deletes from document, records deleted range + contentCutCommand.Unexecute() re-inserts recorded content at recorded range, updates clipboard[CutCmd | BoldCmd | PasteCmd] | (present at end)[CutCmd | BoldCmd | PasteCmd] (present points at CutCmd)[CutCmd | TypeCmd] (BoldCmd and PasteCmd discarded)Example 2: Database Transaction System
Scenario: A database management system needs to support atomic transactions as a sequence of insertions, updates, and deletions. The whole transaction must be undoable as a unit if it fails partway through. Operations need to be logged to disk so they can be replayed after a crash.
Trigger: "We need to group database operations into a transaction and undo the whole thing if any step fails."
Process:
Store() / Load() for crash-recovery logging.InsertCommand captures the inserted row's primary key for Unexecute (DELETE by key). UpdateCommand captures the original row values. DeleteCommand captures the full deleted row.MacroCommand.Unexecute() reverses completed sub-commands in reverse order.Output:
Example 3: Lexi MenuItem-Command Case Study (from GoF)
Scenario: The Lexi document editor (GoF chapter 2) has dozens of user operations accessible via pull-down menus and keyboard shortcuts. Operations include paste, change font, open document, quit, and save. Some are undoable (paste, font change), some are not (quit, save). MenuItems must not be subclassed per operation β one MenuItem class must serve all cases.
Trigger: "We have too many menu item subclasses β one per operation. Adding a new operation requires a new subclass."
Process:
PasteCommand(document): Execute calls document.Paste(). Undoable β stores clipboard content.
- FontCommand(document, font, range): Execute saves original font, applies new font. Undoable.
- OpenCommand(application): Execute prompts user for filename, creates Document, calls application.Add(document), opens it. Not the typical receiver-delegation pattern β the command does all the work itself because there is no pre-existing receiver.
- QuitCommand(application): Execute checks if document is modified; if so, calls save.Execute(), then quits. Reversible() = false β not placed on history.
history.ExecuteCommand(this._command).Output:
history.Undo() β which calls Unexecute() on the last reversible commandFontCommand.Reversible() checks if font actually changed; returns false if not, preventing a no-op undo entryclawhub install bookforge-command-pattern-implementor