Menu
Coddy logo textTech

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 gestoppt

Ausgabe:

Current: Red
Red -> Green
Current: Green
Green -> Yellow
Current: Yellow
Yellow -> Red
Current: Red
Starting music
Already playing
Stopping music
Already stopped

Wichtiger 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.

challenge icon

Aufgabe

Einfach

Implementiere 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.

  • LampState ist die Basisklasse mit press(lamp) und describe().
  • OffState, LowState und HighState implementieren sie: press ruft lamp.set_state(...) mit dem nächsten Zustand auf (aus zu niedrig, niedrig zu hoch, hoch zu aus), und describe gibt Lamp is off, Lamp is on low oder Lamp is on high zurück.
  • Lamp ist der Kontext: Sie startet in OffState, set_state tauscht das Zustandsobjekt aus, press_button delegiert an den aktuellen Zustand, und status gibt 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())
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-Python-Compiler