Menu
Coddy logo textTech

Zustandsmuster

Teil des Abschnitts Object Oriented Programming der Python-Journey von Coddy — Lektion 53 von 64.

Das State Pattern 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 Zustands-Klassen 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 in den nächsten Zustand passiert.

Erstellen Sie eine Kontext-Klasse, die den aktuellen Zustand hält:

class TrafficLight:
    def __init__(self):
        self.state = RedState()  # Beginne mit Rot
    
    def change(self):
        self.state.next_state(self)
    
    def get_color(self):
        return self.state.current_color()

Die Ampel delegiert das Verhalten an ihr aktuelles Zustandsobjekt.

Verwenden Sie 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()}")

Erstellen Sie 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 wird gestartet
player.play()   # Läuft 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

Kernpunkt: Das State Pattern kapselt zustandsspezifisches Verhalten in separaten Klassen und lässt das Kontext-Objekt an den aktuellen Zustand delegieren. Wenn sich der Zustand ändert, ändert sich das Verhalten automatisch. Dies eliminiert komplexe if/else-Anweisungen und macht das Hinzufügen neuer Zustände einfacher.

challenge icon

Aufgabe

Einfach

In dieser Herausforderung implementieren Sie die Klasse State in state.py mit ordnungsgemäßer Kapselung und Methoden. Die Datei enthält detaillierte TODO-Kommentare, die Sie Schritt für Schritt durch Ihre Implementierung führen.

Die Test-Suite ist darauf ausgelegt, zu verifizieren, dass Ihre Implementierung alle Anforderungen erfüllt und Ausnahmezustände korrekt behandelt. Nutzen Sie die Testergebnisse, um das erwartete Verhalten zu verstehen und Ihre Lösung zu verfeinern.

Spickzettel

Das State Pattern (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 wechseln.

Erstellen Sie Zustandsklassen, die das Verhalten für jeden Zustand definieren:

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"

Erstellen Sie eine Kontextklasse, die den aktuellen Zustand hält:

class TrafficLight:
    def __init__(self):
        self.state = RedState()  # Startet mit Rot
    
    def change(self):
        self.state.next_state(self)
    
    def get_color(self):
        return self.state.current_color()

Anwendungsbeispiel:

light = TrafficLight()
print(f"Current: {light.get_color()}")  # Aktuell: Red
light.change()  # Red -> Green
print(f"Current: {light.get_color()}")  # Aktuell: Green

Das State Pattern kapselt zustandsspezifisches Verhalten in separaten Klassen und lässt das Kontextobjekt an den aktuellen Zustand delegieren. Dies eliminiert komplexe if/else-Anweisungen und erleichtert das Hinzufügen neuer Zustände.

Probier es selbst

from state import State

# Umfassender Testfall-Handler
test_case = input()

if test_case == "basic_test":
    obj = State("Test Name")
    obj.display_info()

elif test_case == "validation_test":
    obj = State("Validation Test")
    print(f"Name: {obj.name}")

elif test_case == "empty_name_test":
    obj = State("")
    obj.display_info()
    print(f"Name property: {obj.name}")

elif test_case == "special_chars_test":
    obj = State("Test@#$%")
    obj.display_info()
    print(f"Name property: {obj.name}")

elif test_case == "long_name_test":
    long_name = "A" * 100
    obj = State(long_name)
    obj.display_info()
    print(f"Name length: {len(obj.name)}")

elif test_case == "multiple_states_test":
    states = [
        State("California"),
        State("Texas"),
        State("New York"),
        State("Florida")
    ]
    
    for state in states:
        state.display_info()
        print(f"Name via property: {state.name}")

elif test_case == "attribute_access_test":
    obj = State("Access Test")
    # Direkter Zugriff auf privates Attribut (nicht empfohlen)
    print(f"Direct access (not recommended): {obj._name}")
    # Zugriff über Eigenschaft (empfohlen)
    print(f"Property access (recommended): {obj.name}")

elif test_case == "property_behavior_test":
    obj = State("Original Name")
    print(f"Original name: {obj.name}")
    
    # Versuchen, den Namen zu ändern (wird fehlschlagen, da kein Setter vorhanden ist)
    try:
        obj.name = "New Name"
    except AttributeError as e:
        print(f"Error when trying to modify name: {e}")
    
    # Zeigen, dass der Name unverändert ist
    print(f"Name after modification attempt: {obj.name}")
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 Object Oriented Programming