8.6. Command¶
8.6.1. Rationale¶
EN: Command
PL: Polecenie
Type: object
8.6.2. Use Cases¶
GUI Buttons, menus
Macro recording
Multi level undo/redo (See Tutorial)
Networking — send whole command objects across a network, even as a batch
Parallel processing or thread pools
Transactional behaviour — Rollback whole set of commands, or defer till later
Wizards
Source [medium]
8.6.3. Problem¶
class Button:
__label: str
def set_label(self, name):
self.__label = name
def get_label(self):
return self.__label
def click(self):
...
if __name__ == '__main__':
button = Button()
button.set_label('My Button')
button.click()
8.6.4. Design¶
Receiver — The Object that will receive and execute the command
Invoker — Which will send the command to the receiver
Command Object — Itself, which implements an execute, or action method, and contains all required information
Client — The main application or module which is aware of the Receiver, Invoker and Commands

8.6.5. Implementation¶

Command pattern:
from abc import ABCMeta, abstractmethod
from dataclasses import dataclass
class Command(metaclass=ABCMeta):
@abstractmethod
def execute(self) -> None:
pass
class Button:
__label: str
__command: Command
def __init__(self, command: Command):
self.__command = command
def set_label(self, name):
self.__label = name
def get_label(self):
return self.__label
def click(self):
self.__command.execute()
class CustomerService:
def add_customer(self) -> None:
print('Add customer')
@dataclass
class AddCustomerCommand(Command):
__service: CustomerService
def execute(self) -> None:
self.__service.add_customer()
if __name__ == '__main__':
service = CustomerService()
command = AddCustomerCommand(service)
button = Button(command)
button.click()
# Add customer
Composite commands (Macros):
from abc import ABCMeta, abstractmethod
from dataclasses import dataclass, field
class Command(metaclass=ABCMeta):
@abstractmethod
def execute(self) -> None:
pass
class ResizeCommand(Command):
def execute(self) -> None:
print('Resize')
class BlackAndWhiteCommand(Command):
def execute(self) -> None:
print('Black And White')
@dataclass
class CompositeCommand(Command):
__commands: list[Command] = field(default_factory=list)
def add(self, command: Command) -> None:
self.__commands.append(command)
def execute(self) -> None:
for command in self.__commands:
command.execute()
if __name__ == '__main__':
composite = CompositeCommand()
composite.add(ResizeCommand())
composite.add(BlackAndWhiteCommand())
composite.execute()
# Resize
# Black And White
Undoable commands:
from abc import ABCMeta, abstractmethod
from dataclasses import dataclass, field
class Command(metaclass=ABCMeta):
@abstractmethod
def execute(self) -> None:
pass
class ResizeCommand(Command):
def execute(self) -> None:
print('Resize')
class BlackAndWhiteCommand(Command):
def execute(self) -> None:
print('Black And White')
@dataclass
class CompositeCommand(Command):
__commands: list[Command] = field(default_factory=list)
def add(self, command: Command) -> None:
self.__commands.append(command)
def execute(self) -> None:
for command in self.__commands:
command.execute()
if __name__ == '__main__':
composite = CompositeCommand()
composite.add(ResizeCommand())
composite.add(BlackAndWhiteCommand())
composite.execute()
# Resize
# Black And White