Use Cases For The Command Design Pattern
The Command Pattern has numerous real-world applications across different domains.
Graphic Editors and Word Processors
Graphic editors like Photoshop and
word processors like Microsoft Word use the Command Pattern for implementing
undo and redo functionalities. Each user action (like adding text, applying a
filter, moving an element, etc.) is encapsulated as a command object. When a
user performs an action, a command is executed and added to the history
stack. For an undo operation, the most recent command is taken from the stack
and its undo
method is invoked. This reverses the operation. The Command
Pattern makes it easy to implement this feature as each command knows how to
undo its operation.
This class diagram consists of the ICommand
interface, the DrawCommand
and EraseCommand
classes which implement the ICommand
interface, the Shape
class which represents the receiver object, and the GraphicEditor
class which
acts as the invoker. The DrawCommand
and EraseCommand
classes operate on
the Shape
object, while the GraphicEditor
class invokes commands.
The ICommand
interface has execute()
and undo()
methods. The DrawCommand
and EraseCommand
classes implement these methods. The Shape
class
has draw()
and erase()
methods. The GraphicEditor
class has
an invokeCommand()
method which is used to execute or undo commands, and it
keeps a history of executed commands.
Note: The GraphicEditor
maintains a history of ICommand
objects (represented
by the "1" o--> "*" ICommand: Invokes
line) which allows the implementation of
undo/redo functionality.
Database Transactions
In a database transaction system, operations like
insert, update, or delete can be wrapped as command objects. Each operation
becomes an object with execute
and undo
methods. This can make it easier
to implement features like transactional behavior and rollback operations.
This class diagram consists of the ICommand
interface,
the InsertCommand
, UpdateCommand
and DeleteCommand
classes which implement
the ICommand
interface, the Database
class which represents the receiver
object, and the TransactionManager
class which acts as the invoker.
The InsertCommand
, UpdateCommand
and DeleteCommand
classes operate on
the Database
object, while the TransactionManager
class invokes commands.
The ICommand
interface has execute()
and undo()
methods.
The InsertCommand
, UpdateCommand
and DeleteCommand
classes implement these
methods. The Database
class has insert(data: Data)
, update(data: Data)
and delete(data: Data)
methods. The TransactionManager
class has
an invokeCommand()
method which is used to execute or undo commands, and it
keeps a history of executed commands.
Note: The TransactionManager
maintains a history of ICommand
objects (
represented by the "1" o--> "*" ICommand: Invokes
line) which allows the
implementation of rollback operations.
Queueing and Scheduling Operations
In a system where operations need to be queued or scheduled to be executed later (like in a job queue in a web server, or task scheduler in an operating system), each operation can be encapsulated as a command object. This allows the system to handle operations uniformly, without knowing their specifics. It also enables adding, removing, and reordering of operations easily.
In this diagram, the ICommand
interface, the Task1Command
and Task2Command
classes which implement the ICommand
interface, the Task1
and Task2
classes which represent receiver objects, and the Scheduler
class which acts
as the invoker are present.
The ICommand
interface has an execute()
method. The Task1Command
and Task2Command
classes implement this method. The Task1
and Task2
classes have run()
methods that contain the actual task logic. The Scheduler
class has an addCommand()
method used to add commands to the queue and
a runCommands()
method that executes all commands in the queue.
The Scheduler
maintains a queue of ICommand
objects (represented by
the "1" o--> "*" ICommand: Schedules
line). Task1Command
and Task2Command
classes operate on Task1
and Task2
objects respectively.
Macro Recording
The Command Pattern is useful in scenarios where you need to record sequences of actions as macros and replay them later. Each action is a command that knows how to execute itself. A macro is a sequence of commands. To replay a macro, you simply execute each command in the sequence.
In this diagram, the ICommand
interface, the Command1
and Command2
classes
which implement the ICommand
interface, the Action1
and Action2
classes
which represent receiver objects, and the MacroRecorder
class which acts as
the invoker are present.
The ICommand
interface has an execute()
method. The Command1
and Command2
classes implement this method. The Action1
and Action2
classes have perform()
methods that contain the actual task logic.
The MacroRecorder
class has startRecording()
, stopRecording()
,
and runMacro()
methods that control the recording and execution of macros.
The MacroRecorder
maintains a list of ICommand
objects (represented by
the "1" o--> "*" ICommand: Records
line) which constitute the
macro. Command1
and Command2
classes operate on Action1
and Action2
objects respectively.
In each of these scenarios, the key benefit of the Command Pattern is that it decouples the object that invokes an operation (the invoker) from the object that knows how to perform the operation (the receiver). This allows the system to be more flexible and extensible. It's easier to add new commands, modify existing commands, or change the way commands are triggered, without needing to modify the code of the invoker or the receiver.
Use Cases For The Command Design Pattern
Time To Transition From JavaScript To TypeScript
Level Up Your TypeScript And Object Oriented Programming Skills. The only complete TypeScript course on the marketplace you building TypeScript apps like a PRO.
SEE COURSE DETAILSWhat Can You Do Next 🙏😊
If you liked the article, consider subscribing to Cloudaffle, my YouTube Channel, where I keep posting in-depth tutorials and all edutainment stuff for software developers.