Command Pattern in Software Development

This entry is part 3 of 5 in the series Design Patterns

You can follow along with my github repo where I implement each design pattern individually. Looking at the code can help you internalize the material so I do encourage you to follow the repo for updates as I continue to develop this course: Design Patterns Repo

The Command Pattern is a behavioral design pattern that turns a request into a standalone object containing all the information about the request. This transformation allows parameterizing methods with different requests, delaying or queuing a request's execution, and supporting undoable operations.

The main idea behind this pattern is to decouple the object that invokes the operation from the one that knows how to perform it. This separation provides flexibility in designing systems with customizable or queued operations and improves scalability and testability.

Pattern Structure

The core structure involves:

  1. Command: Declares the interface for executing operations
  2. Concrete Command: Defines a binding between a receiver and an action
  3. Client: Creates and configures commands
  4. Invoker: Asks the command to carry out the request
  5. Receiver: Knows how to perform the operation associated with the command

Real-World Analogy

Imagine a restaurant setting:

  • The waiter takes your order and writes it down (command).
  • The order is then sent to the chef (receiver) who knows how to cook it.
  • The customer (client) doesn't need to know who the chef is or how the food is prepared.
  • The waiter (invoker) simply hands over the order to the kitchen

This separation of responsibilities helps in managing complex systems while maintaining clarity and structure.

Software Use Case

The Command pattern is extensively used in applications that require an undo/redo system. Consider a text editor:

  • Each operation like typing a character, deleting text, or pasting is encapsulated as a command
  • These commands can be stored in a stack, allowing the system to undo or redo them
  • This makes the editor more flexible and reliable by keeping track of changes

Another use case is GUI toolkits where each button can be assigned a command. This decouples the button implementation from the actual business logic.

UML Components

PlantUML Syntax:<br />
@startuml</p>
<p>interface Command {<br />
+execute()<br />
}</p>
<p>class ConcreteCommandA {<br />
+execute()<br />
-receiver: Receiver<br />
}</p>
<p>class ConcreteCommandB {<br />
+execute()<br />
-receiver: Receiver<br />
}</p>
<p>class Receiver {<br />
+action()<br />
}</p>
<p>class Invoker {<br />
-command: Command<br />
+executeCommand()<br />
}</p>
<p>class Client {<br />
+main()<br />
}</p>
<p>Command <|-- ConcreteCommandA<br />
Command <|-- ConcreteCommandB<br />
ConcreteCommandA --> Receiver<br />
ConcreteCommandB --> Receiver<br />
Invoker --> Command<br />
Client --> Invoker<br />
Client --> ConcreteCommandA<br />
Client --> ConcreteCommandB</p>
<p>@enduml<br />

Benefits

  • Decouples sender and receiver: The invoker doesn't need to know how the request is handled
  • Supports undo/redo: You can store commands in history stacks.
  • Easier logging and transaction management: Commands can be serialized or persisted.

Trade-Offs

  • Increased number of classes: Every operation requires a separate command class.
  • Complexity: The pattern can be overkill for simple operations

Best Practices

  • Use when you need parameterization of objects based on an action.
  • Ideal for implementing transactional behaviors or macro recording systems.
  • Avoid using it for trivial actions where the overhead isn't justified.

Example (Dart Implementation)

You can see an implementation of the chain of responsibility design pattern in my design patterns repo: Command Design Pattern

Final Thoughts

The Command pattern is powerful when dealing with complex sequences of actions, or when undo/redo functionality is essential. By encapsulating operations in objects, systems gain modularity, testability, and the ability to support dynamic behaviors. It is an excellent choice for user interfaces, macro systems, and job queues where action decoupling is beneficial.

Article by

Image

Design Patterns

Chain of Responsibility Pattern in Software Development Interpreter Pattern in Software Development
Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments