-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcommand_pattern_demo.py
More file actions
146 lines (112 loc) · 4.14 KB
/
Copy pathcommand_pattern_demo.py
File metadata and controls
146 lines (112 loc) · 4.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
from abc import ABC, abstractmethod
from typing import List
# Receiver: The object that performs the actual work
class Light:
"""The Receiver class that knows how to perform operations."""
def __init__(self, name: str):
self.name = name
self.is_on = False
def turn_on(self):
self.is_on = True
print(f"[{self.name}] Light is now ON")
def turn_off(self):
self.is_on = False
print(f"[{self.name}] Light is now OFF")
# Command Interface
class Command(ABC):
"""The Command abstract base class."""
@abstractmethod
def execute(self) -> None:
pass
@abstractmethod
def undo(self) -> None:
pass
# Concrete Commands
class LightOnCommand(Command):
"""Command to turn on a light."""
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):
"""Command to turn off a light."""
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 MacroCommand(Command):
"""A Command that executes a sequence of other commands."""
def __init__(self, commands: List[Command]):
self.commands = commands
def execute(self) -> None:
print("--- Executing Macro ---")
for command in self.commands:
command.execute()
def undo(self) -> None:
print("--- Undoing Macro ---")
for command in reversed(self.commands):
command.undo()
# Invoker: The object that requests the command to be executed
class SimpleRemoteControl:
"""The Invoker class that triggers commands and manages history for undo."""
def __init__(self):
self.history = []
def press_button(self, command: Command):
"""Execute a command and save it to history."""
command.execute()
self.history.append(command)
def press_undo(self):
"""Undo the last executed command."""
if self.history:
command = self.history.pop()
print(f"Undoing: {command.__class__.__name__}")
command.undo()
else:
print("Nothing to undo.")
def run_demo():
"""Main demonstration logic."""
print("Demonstrating Command Design Pattern in Python:")
print("=" * 60)
# 1. Setup Receivers
living_room_light = Light("Living Room")
kitchen_light = Light("Kitchen")
# 2. Setup Commands
lr_on = LightOnCommand(living_room_light)
lr_off = LightOffCommand(living_room_light)
kitchen_on = LightOnCommand(kitchen_light)
kitchen_off = LightOffCommand(kitchen_light)
# 3. Setup Invoker
remote = SimpleRemoteControl()
# 4. Demonstrate Single Commands
print("Step 1: Operating individual lights")
remote.press_button(lr_on)
remote.press_button(kitchen_on)
print()
# 5. Demonstrate Undo
print("Step 2: Testing Undo")
remote.press_undo() # Should turn off Kitchen light
print()
# 6. Demonstrate Macro Command (Party Mode)
print("Step 3: Macro Command (Party Mode - All Lights ON)")
party_mode = MacroCommand([lr_on, kitchen_on])
remote.press_button(party_mode)
print()
# 7. Undo Macro
print("Step 4: Undoing Macro")
remote.press_undo()
print()
print("Key Takeaways:")
print("- Decouples the object that invokes the operation from the one that knows how to perform it.")
print("- Commands are first-class objects; they can be stored, passed, and manipulated.")
print("- Enables complex features like undo/redo and macro recording.")
print("- New commands can be added without changing existing code (Open/Closed Principle).")
if __name__ == "__main__":
run_demo()
# The Command Design Pattern encapsulates a request as an object, thereby letting
# you parameterize clients with different requests, queue or log requests,
# and support undoable operations. It's widely used in UI frameworks for
# button actions and in systems requiring transactional history.