Befehlsmuster
Teil des Abschnitts Objektorientierte Programmierung der Python-Journey von Coddy. Lektion 49 von 64.
Das Command Pattern kapselt eine Anfrage als Objekt und ermöglicht es dir, Vorgänge in eine Warteschlange einzureihen, Anfragen zu protokollieren und eine Rückgängig-Funktion zu unterstützen. Es trennt das Objekt, das den Vorgang aufruft, von demjenigen, das ihn 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 bestimmte Operation in einem receiver-Objekt.
Erstelle den receiver, der die eigentliche Arbeit ausführt:
class Light:
def turn_on(self):
print("Light is on")
def turn_off(self):
print("Light is off")Erstelle einen Aufrufer, 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()Verwende das Befehlsmuster:
# 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()Füge Unterstützung für undo-Operationen hinzu:
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 offWichtiger Punkt: Das Command Pattern verwandelt Anfragen in Objekte, die gespeichert, weitergereicht und später ausgeführt werden können. Der Aufrufer muss nicht wissen, wie die Operation ausgeführt wird – er ruft einfach execute() für das Befehlsobjekt auf. Dies ermöglicht Funktionen wie Rückgängigmachen/Wiederholen, das Einreihen von Operationen und das Protokollieren von Befehlen.
Aufgabe
EinfachIn dieser Herausforderung implementierst du die grundlegende Command-Basisklasse in command.py: den wesentlichen Baustein des Command Patterns. Diese Übung konzentriert sich speziell auf Kapselung: Daten privat zu speichern und sie sicher über eine Property bereitzustellen.
Ändere nur command.py entsprechend den TODO-Kommentaren. Die TODO-Kommentare führen dich zu folgenden Aufgaben:
- Den Befehlsnamen als privates Attribut (
_name) speichern - Den Namen über eine schreibgeschützte Property (
name) bereitstellen - Eine
display_info()-Methode implementieren, die den Befehlsnamen ausgibt
Hinweis: Diese Herausforderung behandelt nur die grundlegende Command-Klasse: Der Aufrufer, der Empfänger und die Rückgängig-Funktion werden in späteren Lektionen eingeführt. Mit diesem Schritt legst du die Kapselungsgrundlage, auf der das vollständige Muster aufbaut.
Deine Implementierung wird von driver.py getestet, das Folgendes überprüft:
- Grundlegende Funktionalität und Ausgabeformat
- Sonderfälle (leere Eingaben, Sonderzeichen, lange Namen)
- Schutz der schreibgeschützten Property (der Versuch,
obj.name = ...zu setzen, sollteAttributeErrorauslösen) - Das Vorhandensein des privaten Attributs
_name
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 Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDer self-ParameterMethodenAttributeKonstruktormethode (__init__)Zusammenfassung – Einfacher Taschenrechner4Vererbung
Grundlegende VererbungDie super()-FunktionMethodenüberschreibungMehrfachvererbungMethodenauflösungsreihenfolgeWiederholung – Mitarbeiterhierarchie7Spezielle Methoden
Einführung in magische MethodenOperatorüberladungMagische Methoden für ContainerRückblick – Benutzerdefinierte Liste10Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster13Abschließende Herausforderungen
E-Learning-PlattformBankensystemEntwicklung von SpielfigurenFahrzeugvermietungsservice2Dekoratoren
Einführung in DekoratorenProperty-DekoratorDekorator für statische MethodenDekorator für Klassenmethoden5Polymorphie
Methodenüberschreibung erneut betrachtetDuck-TypingAbstrakte Klassen und MethodenSchnittstellendesignRückblick – Formrechner8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungMixinsStatische Methoden und KlassenmethodenKlassen-DekoratorenKontextmanager11Entwurfsmuster Teil 2
BefehlsmusterAdaptermusterDekorierermusterSchablonenmethodenmusterZustandsmusterKompositumsmuster3Klassenattribute
Instanz- vs. KlassenvariablenProperty-DecoratorsPrivate AttributeWiederholung – Bankkontoverwaltung6Kapselung
Öffentliche, geschützte, private MemberZugriffsmodifikatorenInformationsverbergungProperty-Decorators – FortgeschrittenWiederholung – System zur Verwaltung von Studentendaten12Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und BenutzerklassenAusleihsystemSuchfunktionAdministrationsoberflächeTests und IntegrationÜbe selbstständig: Online-Python-Compiler