Claude Artifact

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:

  1. Commands as Objects:
  2. Real-world Uses:
  3. Key Benefits:

Sweet dreams! When you wake up, we can explore:

  1. How to add scheduling to commands
  2. How to persist commands for automation
  3. How to implement more complex macro scenarios

Would love to show you more cool patterns tomorrow! 🌙