Zustandsmuster
Teil des Abschnitts Objektorientierte Programmierung der Python-Journey von Coddy. Lektion 53 von 64.
Das Zustandsmuster ermöglicht es einem Objekt, sein Verhalten zu ändern, wenn sich sein interner Zustand ändert. Das Objekt scheint seine Klasse basierend auf seinem aktuellen Zustand zu ändern.
Hier sind einfache Zustandsklassen für eine Ampel:
class RedState:
def next_state(self, light):
print("Red -> Green")
light.state = GreenState()
def current_color(self):
return "Red"
class GreenState:
def next_state(self, light):
print("Green -> Yellow")
light.state = YellowState()
def current_color(self):
return "Green"
class YellowState:
def next_state(self, light):
print("Yellow -> Red")
light.state = RedState()
def current_color(self):
return "Yellow"Jeder Zustand definiert, was beim Übergang zum nächsten Zustand geschieht.
Erstelle eine Kontextklasse, die den aktuellen Zustand enthält:
class TrafficLight:
def __init__(self):
self.state = RedState() # Mit Rot starten
def change(self):
self.state.next_state(self)
def get_color(self):
return self.state.current_color()Die Ampel delegiert ihr Verhalten an ihr aktuelles Zustandsobjekt.
Verwende die Ampel:
light = TrafficLight()
print(f"Current: {light.get_color()}")
light.change() # Rot -> Grün
print(f"Current: {light.get_color()}")
light.change() # Grün -> Gelb
print(f"Current: {light.get_color()}")
light.change() # Gelb -> Rot
print(f"Current: {light.get_color()}")Erstelle ein weiteres Beispiel mit einem einfachen Player:
class PlayingState:
def play(self, player):
print("Already playing")
def stop(self, player):
print("Stopping music")
player.state = StoppedState()
class StoppedState:
def play(self, player):
print("Starting music")
player.state = PlayingState()
def stop(self, player):
print("Already stopped")
class MusicPlayer:
def __init__(self):
self.state = StoppedState()
def play(self):
self.state.play(self)
def stop(self):
self.state.stop(self)
player = MusicPlayer()
player.play() # Musik startet
player.play() # Spielt bereits
player.stop() # Musik wird gestoppt
player.stop() # Bereits gestopptAusgabe:
Current: Red
Red -> Green
Current: Green
Green -> Yellow
Current: Yellow
Yellow -> Red
Current: Red
Starting music
Already playing
Stopping music
Already stoppedWichtiger Punkt: Das Zustandsmuster kapselt zustandsspezifisches Verhalten in separaten Klassen und ermöglicht es dem Kontextobjekt, an den aktuellen Zustand zu delegieren. Wenn sich der Zustand ändert, ändert sich das Verhalten automatisch. Dadurch entfallen komplexe if/else-Anweisungen, und das Hinzufügen neuer Zustände wird erleichtert.
Aufgabe
EinfachImplementiere das State-Muster in state.py für eine Lampe mit einer Taste. Jeder Tastendruck bewegt die Lampe durch drei Zustände in einem Zyklus: aus, niedrig, hoch und zurück zu aus. Statt einer if-Kette mit einem String ist jeder Zustand ein eigenes Objekt, das weiß, was beim Drücken der Taste geschieht.
LampStateist die Basisklasse mitpress(lamp)unddescribe().OffState,LowStateundHighStateimplementieren sie:pressruftlamp.set_state(...)mit dem nächsten Zustand auf (aus zu niedrig, niedrig zu hoch, hoch zu aus), unddescribegibtLamp is off,Lamp is on lowoderLamp is on highzurück.Lampist der Kontext: Sie startet inOffState,set_statetauscht das Zustandsobjekt aus,press_buttondelegiert an den aktuellen Zustand, undstatusgibt die aktuelle Beschreibung zurück.
driver.py ist gesperrt: Es drückt die Taste und gibt den Status aus. Beachte, dass Lamp niemals prüft, in welchem Zustand sie sich befindet; die Zustandsobjekte entscheiden.
Probier es selbst
from state import Lamp
# Testfall-Handler (nicht ändern)
test_case = input()
lamp = Lamp()
if test_case == "initial_test":
print(lamp.status())
elif test_case == "one_press_test":
lamp.press_button()
print(lamp.status())
elif test_case == "cycle_test":
for _ in range(4):
print(lamp.status())
lamp.press_button()
elif test_case == "many_presses_test":
for _ in range(7):
lamp.press_button()
print(lamp.status())
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