Command-Muster
Teil des Abschnitts Object Oriented Programming der Python-Journey von Coddy — Lektion 49 von 64.
Das Command Pattern kapselt eine Anfrage als Objekt, was es ermöglicht, Operationen in eine Warteschlange zu stellen, Anfragen zu protokollieren und eine Rückgängig-Funktionalität zu unterstützen. Es trennt das Objekt, das die Operation aufruft, von demjenigen, das sie ausführt.
Hier sind einfache Befehlsklassen:
class Command:
def execute(self):
pass
class LightOnCommand(Command):
def __init__(self, light):
self.light = light
def execute(self):
self.light.turn_on()
class LightOffCommand(Command):
def __init__(self, light):
self.light = light
def execute(self):
self.light.turn_off()Jeder Befehl kapselt eine spezifische Operation auf einem Empfängerobjekt.
Erstellen Sie den Receiver, der die eigentliche Arbeit verrichtet:
class Light:
def turn_on(self):
print("Light is on")
def turn_off(self):
print("Light is off")Erstellen Sie einen Invoker, der Befehle ausführt:
class RemoteControl:
def __init__(self):
self.command = None
def set_command(self, command):
self.command = command
def press_button(self):
self.command.execute()Verwenden Sie das Command-Pattern:
# Empfänger erstellen
light = Light()
# Befehle erstellen
light_on = LightOnCommand(light)
light_off = LightOffCommand(light)
# Aufrufer (Invoker) erstellen
remote = RemoteControl()
# Verschiedene Befehle ausführen
remote.set_command(light_on)
remote.press_button()
remote.set_command(light_off)
remote.press_button()Unterstützung für Rückgängig-Operationen hinzufügen:
class UndoableCommand(Command):
def undo(self):
pass
class LightOnCommand(UndoableCommand):
def __init__(self, light):
self.light = light
def execute(self):
self.light.turn_on()
def undo(self):
self.light.turn_off()
class SmartRemote:
def __init__(self):
self.last_command = None
def execute_command(self, command):
command.execute()
self.last_command = command
def undo(self):
if self.last_command:
self.last_command.undo()
smart_remote = SmartRemote()
smart_remote.execute_command(LightOnCommand(light))
smart_remote.undo() # Schaltet das Licht ausAusgabe:
Light is on
Light is off
Light is on
Light is offKernpunkt: Das Command-Pattern wandelt Anfragen in Objekte um, die gespeichert, weitergegeben und später ausgeführt werden können. Der Aufrufer (Invoker) muss nicht wissen, wie die Operation ausgeführt wird – er ruft lediglich execute() auf dem Befehlsobjekt auf. Dies ermöglicht Funktionen wie Rückgängigmachen/Wiederholen, das Einreihen von Operationen in Warteschlangen und das Protokollieren von Befehlen.
Aufgabe
EinfachIn dieser Herausforderung implementieren Sie die grundlegende Command-Basisklasse in command.py — den wesentlichen Baustein des Command-Patterns. Diese Übung konzentriert sich speziell auf die Kapselung: das private Speichern von Daten und deren sichere Bereitstellung über ein Property.
Ändern Sie nur command.py gemäß den TODO-Kommentaren. Die TODO-Kommentare führen Sie dazu:
- Speichern Sie den Befehlsnamen als privates Attribut (
_name) - Stellen Sie ihn über ein schreibgeschütztes Property (
name) bereit - Implementieren Sie eine
display_info()-Methode, die den Befehlsnamen ausgibt
Hinweis: Diese Herausforderung deckt nur die Basisklasse Command ab — Invoker, Receiver und die Undo-Funktionalität werden in späteren Lektionen eingeführt. Das Abschließen dieses Schritts bietet Ihnen die Kapselungsgrundlage, auf der das vollständige Pattern aufbaut.
Ihre Implementierung wird durch driver.py getestet, welche Folgendes validiert:
- Grundlegende Funktionalität und Ausgabeformat
- Grenzfälle (leere Eingaben, Sonderzeichen, lange Namen)
- Schutz des schreibgeschützten Propertys (der Versuch
obj.name = ...sollte einenAttributeErrorauslösen) - Vorhandensein des privaten Attributs
_name
Spickzettel
Das Command-Pattern kapselt eine Anfrage als Objekt und ermöglicht es Ihnen, Operationen in eine Warteschlange zu stellen, Anfragen zu protokollieren und eine Rückgängig-Funktionalität zu unterstützen.
Grundlegende Befehlsstruktur:
class Command:
def execute(self):
pass
class LightOnCommand(Command):
def __init__(self, light):
self.light = light
def execute(self):
self.light.turn_on()
class LightOffCommand(Command):
def __init__(self, light):
self.light = light
def execute(self):
self.light.turn_off()Erstellen Sie einen Empfänger (Receiver), der die eigentliche Arbeit verrichtet:
class Light:
def turn_on(self):
print("Light is on")
def turn_off(self):
print("Light is off")Erstellen Sie einen Aufrufer (Invoker), der Befehle ausführt:
class RemoteControl:
def __init__(self):
self.command = None
def set_command(self, command):
self.command = command
def press_button(self):
self.command.execute()Anwendungsbeispiel:
# Empfänger erstellen
light = Light()
# Befehle erstellen
light_on = LightOnCommand(light)
light_off = LightOffCommand(light)
# Aufrufer erstellen
remote = RemoteControl()
# Verschiedene Befehle ausführen
remote.set_command(light_on)
remote.press_button()
remote.set_command(light_off)
remote.press_button()Rückgängig-Funktionalität hinzufügen:
class UndoableCommand(Command):
def undo(self):
pass
class LightOnCommand(UndoableCommand):
def __init__(self, light):
self.light = light
def execute(self):
self.light.turn_on()
def undo(self):
self.light.turn_off()
class SmartRemote:
def __init__(self):
self.last_command = None
def execute_command(self, command):
command.execute()
self.last_command = command
def undo(self):
if self.last_command:
self.last_command.undo()Probier es selbst
# Importiere die Command-Klasse aus command.py
from command import Command
# Umfassender Testfall-Handler
test_case = input()
if test_case == "basic_test":
obj = Command("Test Name")
obj.display_info()
elif test_case == "validation_test":
obj = Command("Validation Test")
print(f"Name: {obj.name}")
elif test_case == "empty_name_test":
obj = Command("")
obj.display_info()
print(f"Empty name handled: {'Yes' if obj.name == '' else 'No'}")
elif test_case == "property_access_test":
obj = Command("Property Test")
original_name = obj.name
try:
# Dies sollte fehlschlagen, da name eine schreibgeschützte Eigenschaft ist
obj.name = "Modified Name"
print("Property protection failed")
except AttributeError:
print("Property protected successfully")
print(f"Name unchanged: {obj.name == original_name}")
elif test_case == "multiple_commands_test":
commands = [
Command("First Command"),
Command("Second Command"),
Command("Third Command")
]
for cmd in commands:
cmd.display_info()
elif test_case == "attribute_test":
obj = Command("Attribute Test")
has_private_name = hasattr(obj, "_name")
print(f"Has _name attribute: {has_private_name}")
elif test_case == "special_chars_test":
obj = Command("!@#$%^&*()_+{}[]|\\:;\"'<>,.?/")
obj.display_info()
elif test_case == "long_name_test":
long_name = "A" * 100
obj = Command(long_name)
obj.display_info()
print(f"Name length: {len(obj.name)}")Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Object Oriented Programming
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDer self-ParameterMethodenAttributeKonstruktor-Methode (__init__)Zusammenfassung – Einfacher Taschenrechner4Vererbung
Grundlagen der VererbungDie super()-FunktionMethoden überschreibenMehrfachvererbungMethod Resolution OrderZusammenfassung - Mitarbeiter-Hierarchie7Spezielle Methoden
Einführung in Magic MethodsOperator-ÜberladungMagic Methods für ContainerRückblick - Eigene Liste10Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster13Abschlussherausforderungen
E-Learning-PlattformBanksystemSpielcharakter-EntwicklungFahrzeugvermietung2Dekoratoren
Einführung in DekoratorenProperty-DekoratorStatischer Methoden-DekoratorKlassenmethoden-Dekorator5Polymorphismus
Methoden-Überschreiben vertieftDuck TypingAbstrakte Klassen und MethodenInterface-DesignZusammenfassung – Formen-Rechner8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungMixinsStatische und KlassenmethodenKlassendekoratorenContext Manager11Entwurfsmuster Teil 2
Command-MusterAdapter-MusterDecorator-MusterTemplate-Method-MusterZustandsmusterKompositum-Muster3Klasseneigenschaften
Instanz- vs. KlassenvariablenProperty-DekoratorenPrivate AttributeZusammenfassung – Bankkonto-Manager6Kapselung
Public, Protected, Private MemberZugriffsmodifikatorenInformation HidingProperty-Decorators für FortgeschritteneZusammenfassung - Studentenverwaltungssystem12Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen