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à fermaOutput:
Current: Red
Red -> Green
Current: Green
Green -> Yellow
Current: Yellow
Yellow -> Red
Current: Red
Starting music
Already playing
Stopping music
Already stoppedPunto 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.
Sfida
FacileImplementa 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 conpress(lamp)edescribe().OffState,LowStateeHighStateli implementano:presschiamalamp.set_state(...)con lo stato successivo (da spenta a bassa, da bassa ad alta, da alta a spenta) edescriberestituisceLamp is off,Lamp is on lowoLamp is on high.Lampè il contesto: inizia inOffState,set_statesostituisce l’oggetto stato,press_buttondelega allo stato corrente estatusrestituisce 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())
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
1Fondamenti di OOP
File esterniIntroduzione a OOPClassi vs. oggettiIl parametro selfMetodiAttributiMetodo costruttore (__init__)Riepilogo - Calcolatrice semplice4Ereditarietà
Ereditarietà di baseLa funzione super()Sovrascrittura dei metodiEreditarietà multiplaOrdine di risoluzione dei metodiRiepilogo - Gerarchia dei dipendenti7Metodi speciali
Introduzione ai metodi magiciSovraccarico degli operatoriMetodi magici dei contenitoriRiepilogo - Lista personalizzata10Modelli di progettazione Parte 1
Introduzione ai modelli di progettazioneModello SingletonModello FactoryModello ObserverModello Strategy2Decoratori
Introduzione ai decoratoriDecoratore di proprietàDecoratore di metodo staticoDecoratore di metodo di classe5Polimorfismo
Ripasso dell'override dei metodiDuck typingClassi e metodi astrattiProgettazione delle interfacceRiepilogo - Calcolatore di forme8Concetti avanzati di OOP
Composizione vs ereditarietàMixinMetodi statici e di classeDecorator di classeContext manager11Pattern di progettazione - Parte 2
Pattern dei comandiPattern adattatorePattern decoratorePattern metodo templatePattern statoPattern composito3Proprietà delle classi
Variabili di istanza e di classeDecorator delle proprietàAttributi privatiRiepilogo - Gestore di conti bancari6Incapsulamento
Membri pubblici, protetti e privatiModificatori di accessoOccultamento delle informazioniDecorator delle proprietà: avanzatiRipasso - Sistema di registri degli studenti12Progetto: Gestione della biblioteca
Panoramica del progettoClassi Libro e UtenteSistema di prestitoFunzionalità di ricercaInterfaccia amministratoreTest e integrazioneEsercitati da solo: Compilatore Python online