Menu
Coddy logo textTech

Pattern stato

Fa parte della sezione Programmazione orientata agli oggetti del percorso Python di Coddy. Lezione 53 di 64.

Il pattern State consente a un oggetto di cambiare comportamento quando cambia il suo stato interno. L’oggetto sembra cambiare classe in base al suo stato attuale.

Ecco semplici classi di stato per un semaforo:

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"

Ogni stato definisce cosa accade durante la transizione allo stato successivo.

Crea una classe contesto che mantenga lo stato corrente:

class TrafficLight:
    def __init__(self):
        self.state = RedState()  # Inizia con il rosso
    
    def change(self):
        self.state.next_state(self)
    
    def get_color(self):
        return self.state.current_color()

Il semaforo delega il comportamento al suo oggetto di stato corrente.

Usa il semaforo:

light = TrafficLight()
print(f"Current: {light.get_color()}")

light.change()  # Rosso -> Verde
print(f"Current: {light.get_color()}")

light.change()  # Verde -> Giallo
print(f"Current: {light.get_color()}")

light.change()  # Giallo -> Rosso
print(f"Current: {light.get_color()}")

Crea un altro esempio con un semplice lettore:

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()   # Avvio della musica
player.play()   # La musica è già in riproduzione
player.stop()   # Arresto della musica
player.stop()   # La musica è già ferma

Output:

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

Punto chiave: il pattern State incapsula il comportamento specifico di ciascuno stato in classi separate e consente all’oggetto contesto di delegare allo stato corrente. Quando lo stato cambia, il comportamento cambia automaticamente. Questo elimina le istruzioni if/else complesse e semplifica l’aggiunta di nuovi stati.

challenge icon

Sfida

Facile

Implementa il pattern State in state.py per una lampada con un pulsante. Ogni pressione fa passare la lampada attraverso tre stati in ciclo: spenta, bassa, alta e di nuovo spenta. Invece di una catena di if su una stringa, ogni stato è un proprio oggetto che sa cosa succede quando si preme il pulsante.

  • LampState è la classe base con press(lamp) e describe().
  • OffState, LowState e HighState li implementano: press chiama lamp.set_state(...) con lo stato successivo (da spenta a bassa, da bassa ad alta, da alta a spenta) e describe restituisce Lamp is off, Lamp is on low o Lamp is on high.
  • Lamp è il contesto: inizia in OffState, set_state sostituisce l’oggetto stato, press_button delega allo stato corrente e status restituisce la descrizione corrente.

driver.py è bloccato: preme il pulsante e stampa lo stato. Nota che Lamp non controlla mai in quale stato si trova; sono gli oggetti stato a decidere.

Provalo tu

from state import Lamp

# Gestore dei casi di test (non modificare)
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 iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore Python online