Let me introduce you to the fascinating concept of the Command Pattern, which turns requests into objects. It's like having a universal remote control for your code!
from abc import ABC, abstractmethod
from typing import List
from dataclasses import dataclass
from datetime import datetime
# Commands
class Command(ABC):
@abstractmethod
def execute(self) -> None:
pass
@abstractmethod
def undo(self) -> None:
pass
# Smart Devices (Receivers)
class Light:
def __init__(self, location: str):
self.location = location
self.is_on = False
self.brightness = 0
def turn_on(self) -> None:
self.is_on = True
print(f"{self.location} light turned on")
def turn_off(self) -> None:
self.is_on = False
print(f"{self.location} light turned off")
def dim(self, level: int) -> None:
self.brightness = level
print(f"{self.location} light dimmed to {level}%")
class Thermostat:
def __init__(self, location: str):
self.location = location
self.temperature = 20
def set_temperature(self, temperature: int) -> None:
self.temperature = temperature
print(f"{self.location} thermostat set to {temperature}°C")
# Concrete Commands
class LightOnCommand(Command):
def __init__(self, light: Light):
self.light = light
def execute(self) -> None:
self.light.turn_on()
def undo(self) -> None:
self.light.turn_off()
class LightOffCommand(Command):
def __init__(self, light: Light):
self.light = light
def execute(self) -> None:
self.light.turn_off()
def undo(self) -> None:
self.light.turn_on()
class SetThermostatCommand(Command):
def __init__(self, thermostat: Thermostat, temperature: int):
self.thermostat = thermostat
self.temperature = temperature
self.previous_temperature = thermostat.temperature
def execute(self) -> None:
self.previous_temperature = self.thermostat.temperature
self.thermostat.set_temperature(self.temperature)
def undo(self) -> None:
self.thermostat.set_temperature(self.previous_temperature)
# Macro Command (Composite Command)
class MacroCommand(Command):
def __init__(self, commands: List[Command]):
self.commands = commands
def execute(self) -> None:
for command in self.commands:
command.execute()
def undo(self) -> None:
# Undo commands in reverse order
for command in reversed(self.commands):
command.undo()
# Command History
@dataclass
class CommandHistory:
command: Command
timestamp: datetime
# Smart Home Controller (Invoker)
class SmartHomeController:
def __init__(self):
self.command_history: List[CommandHistory] = []
self.undo_stack: List[Command] = []
def execute_command(self, command: Command) -> None:
command.execute()
self.command_history.append(
CommandHistory(command, datetime.now())
)
self.undo_stack.append(command)
def undo_last_command(self) -> None:
if self.undo_stack:
command = self.undo_stack.pop()
command.undo()
print("Undid last command")
else:
print("No commands to undo")
def show_history(self) -> None:
print("\\\\nCommand History:")
for entry in self.command_history:
print(f"- {entry.command.__class__.__name__} at {entry.timestamp}")
def main():
# Create devices
living_room_light = Light("Living Room")
bedroom_light = Light("Bedroom")
living_room_thermostat = Thermostat("Living Room")
# Create controller
controller = SmartHomeController()
# Create commands
light_on = LightOnCommand(living_room_light)
bedroom_light_on = LightOnCommand(bedroom_light)
set_temp = SetThermostatCommand(living_room_thermostat, 22)
# Create a macro command for "Coming Home" scenario
coming_home = MacroCommand([
LightOnCommand(living_room_light),
SetThermostatCommand(living_room_thermostat, 21)
])
# Execute some commands
print("=== Executing individual commands ===")
controller.execute_command(light_on)
controller.execute_command(bedroom_light_on)
controller.execute_command(set_temp)
# Undo last command
print("\\\\n=== Undoing last command ===")
controller.undo_last_command()
# Execute macro command
print("\\\\n=== Executing 'Coming Home' macro ===")
controller.execute_command(coming_home)
# Show command history
controller.show_history()
if __name__ == "__main__":
main()
The Command Pattern is like having a universal remote control for your code. Here's what makes it special:
Sweet dreams! When you wake up, we can explore:
Would love to show you more cool patterns tomorrow! 🌙