The Command pattern turns a request into a stand-alone object that contains all information about the request. This allows you to parameterize methods with different requests, delay or queue a request's execution, and support undoable operations.
To implement this pattern, you need four components:
- Command Interface: An abstract base class defining the
execute() method. - Concrete Commands: Classes that implement
execute(). They can either perform simple operations themselves (like SimpleCommand) or delegate complex logic to a Receiver (like ComplexCommand). - Receiver: The class that contains the actual business logic and knows how to perform the operations requested by the commands.
- Invoker: The class that triggers the command. It does not depend on concrete command or receiver classes; it simply calls
execute() on the command objects it holds.
from abc import ABC, abstractmethod
# 1. Command Interface
class Command(ABC):
@abstractmethod
def execute(self) -> None:
pass
# 2. Concrete Command (Simple)
class SimpleCommand(Command):
def __init__(self, payload: str) -> None:
self._payload = payload
def execute(self) -> None:
print(f"SimpleCommand: {self._payload}")
# 2. Concrete Command (Complex with Receiver)
class ComplexCommand(Command):
def __init__(self, receiver: Receiver, a: str, b: str) -> None:
self._receiver = receiver
self._a = a
self._b = b
def execute(self) -> None:
self._receiver.do_something(self._a)
self._receiver.do_something_else(self._b)
# 3. Receiver
class Receiver:
def do_something(self, a: str) -> None:
print(f"Receiver: Working on {a}")
def do_something_else(self, b: str) -> None:
print(f"Receiver: Also working on {b}")
# 4. Invoker
class Invoker:
def __init__(self) -> None:
self._on_start = None
self._on_finish = None
def set_on_start(self, command: Command):
self._on_start = command
def set_on_finish(self, command: Command):
self._on_finish = command
def do_something_important(self) -> None:
if isinstance(self._on_start, Command):
self._on_start.execute()
print("Invoker: Doing something important...")
if isinstance(self._on_finish, Command):
self._on_finish.execute()