๐งพ Command Design Pattern: Encapsulating Actions for Total Control
The Command Design Pattern is a behavioral pattern that encapsulates a request as an object, thereby allowing you to parameterize clients with queues, requests, and operations. It’s especially useful for implementing undo/redo, transactional behavior, and decoupled execution.
Think of it like a remote control: each button represents a command, and pressing it triggers a specific action without needing to know how it works internally.
๐ง Core Concept
The Command Pattern turns a request into a standalone object that contains all the information needed to perform the action. This includes:
- The method to call
- The object that owns the method
- Any parameters required
๐ Key Components:
- Command Interface: Declares the
execute()method. - Concrete Command: Implements the command and defines the binding between a receiver and an action.
- Receiver: Knows how to perform the operation.
- Invoker: Stores and invokes commands.
- Client: Configures commands and associates them with receivers.
๐งฑ Structure Overview
+---------+ +----------------+ +-------------+
| Client |-----> | ConcreteCommand |----->| Receiver |
+---------+ +----------------+ +-------------+
^
|
+-------------+
| Command |
+-------------+
^
|
+-------------+
| Invoker |
+-------------+
๐ง๐ป Code Example (in Python)
Let’s simulate a remote control for a light:
# Command Interface
class Command:
def execute(self):
raise NotImplementedError
# Receiver
class Light:
def turn_on(self):
print("Light is ON")
def turn_off(self):
print("Light is OFF")
# Concrete Commands
class LightOnCommand(Command):
def __init__(self, light: Light):
self.light = light
def execute(self):
self.light.turn_on()
class LightOffCommand(Command):
def __init__(self, light: Light):
self.light = light
def execute(self):
self.light.turn_off()
# Invoker
class RemoteControl:
def __init__(self):
self._commands = []
def submit(self, command: Command):
self._commands.append(command)
command.execute()
# Usage
light = Light()
remote = RemoteControl()
remote.submit(LightOnCommand(light))
remote.submit(LightOffCommand(light))
✅ Benefits of Command Pattern
- Decouples sender and receiver: The invoker doesn’t need to know the details of the action.
- Supports undo/redo: Commands can be stored and reversed.
- Flexible and extensible: New commands can be added without changing existing code.
- Macro commands: Combine multiple commands into one.
๐ซ When Not to Use It
- If the action is simple and doesn’t require encapsulation.
- When performance is critical and command overhead is unnecessary.
- If the system doesn’t benefit from decoupling or extensibility.
๐ง Real-World Use Cases
| Use Case | Example |
|---|---|
| GUI buttons | Save, open, close actions |
| Undo/redo systems | Text editors, drawing apps |
| Task scheduling | Job queues, cron systems |
| Home automation | Smart device commands |
| Game development | Player actions, AI commands |
๐ Variants and Enhancements
- Composite Commands: Group multiple commands into one.
- Undoable Commands: Add
undo()method for reversible actions. - Command Queues: Store and execute commands asynchronously.
- Transactional Commands: Rollback on failure.
๐ฌ Final Thoughts
The Command Pattern is a powerful tool for building modular, extensible, and maintainable systems. It shines in scenarios where actions need to be queued, logged, undone, or executed later.
Whether you're designing a GUI, a game engine, or a job scheduler, the Command Pattern gives you the flexibility to manage actions with precision and clarity.
No comments:
Post a Comment