Patron État
Fait partie de la section Programmation orientée objet du Journey Python de Coddy. Leçon 53 sur 64.
Le modèle State permet à un objet de modifier son comportement lorsque son état interne change. L’objet semble changer de classe en fonction de son état actuel.
Voici de simples classes d’état pour un feu de circulation :
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"Chaque état définit ce qui se passe lors de la transition vers l’état suivant.
Créez une classe de contexte qui contient l’état actuel :
class TrafficLight:
def __init__(self):
self.state = RedState() # Commence avec le rouge
def change(self):
self.state.next_state(self)
def get_color(self):
return self.state.current_color()Le feu de circulation délègue son comportement à son objet d’état actuel.
Utilisez le feu de circulation :
light = TrafficLight()
print(f"Current: {light.get_color()}")
light.change() # Rouge -> Vert
print(f"Current: {light.get_color()}")
light.change() # Vert -> Jaune
print(f"Current: {light.get_color()}")
light.change() # Jaune -> Rouge
print(f"Current: {light.get_color()}")Créez un autre exemple avec un lecteur simple :
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() # Démarrage de la musique
player.play() # Déjà en lecture
player.stop() # Arrêt de la musique
player.stop() # Déjà arrêtéSortie :
Current: Red
Red -> Green
Current: Green
Green -> Yellow
Current: Yellow
Yellow -> Red
Current: Red
Starting music
Already playing
Stopping music
Already stoppedPoint clé : le pattern State encapsule le comportement propre à chaque état dans des classes distinctes et permet à l’objet contexte de déléguer à l’état actuel. Lorsque l’état change, le comportement change automatiquement. Cela élimine les instructions if/else complexes et facilite l’ajout de nouveaux états.
Défi
FacileImplémente le patron State dans state.py pour une lampe dotée d’un bouton. Chaque pression fait passer la lampe par trois états selon un cycle : éteinte, faible, forte, puis de nouveau à l’état éteint. Au lieu d’une chaîne de conditions if basée sur une chaîne de caractères, chaque état est son propre objet, qui sait ce qui se passe lorsque le bouton est pressé.
LampStateest la classe de base avecpress(lamp)etdescribe().OffState,LowStateetHighStateles implémentent :pressappellelamp.set_state(...)avec l’état suivant (de éteinte à faible, de faible à forte, de forte à éteinte) etdescriberenvoieLamp is off,Lamp is on lowouLamp is on high.Lampest le contexte : il démarre dansOffState,set_stateremplace l’objet représentant l’état,press_buttondélègue à l’état actuel, etstatusrenvoie la description actuelle.
driver.py est verrouillé : il appuie sur le bouton et affiche l’état. Remarque que Lamp ne vérifie jamais dans quel état elle se trouve ; ce sont les objets représentant les états qui en décident.
Essayez vous-même
from state import Lamp
# Gestionnaire de cas de test (ne pas modifier)
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())
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation orientée objet
1Les fondamentaux de la POO
Fichiers externesIntroduction à la POOClasses vs ObjetsLe paramètre selfMéthodesAttributsMéthode constructeur (__init__)Récapitulatif - Calculatrice simple4Héritage
Héritage de baseLa fonction super()Redéfinition de méthodeHéritage multipleOrdre de résolution des méthodesRécapitulatif - Hiérarchie des employés7Méthodes spéciales
Introduction aux méthodes magiquesSurcharge d'opérateursMéthodes magiques de conteneurRécapitulatif - Liste personnalisée10Patrons de conception, Partie 1
Introduction aux patrons de conceptionPatron SingletonPatron FactoryPatron ObserverPatron Strategy2Décorateurs
Introduction aux décorateursDécorateur de propriétéDécorateur de méthode statiqueDécorateur de méthode de classe5Polymorphisme
Retour sur la redéfinition de méthodeDuck TypingClasses et méthodes abstraitesConception d'interfacesRécapitulatif - Calculateur de formes8Concepts avancés de la POO
Composition vs HéritageMixinsMéthodes statiques et de classeDécorateurs de classeGestionnaires de contexte11Patrons de conception, Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Méthode TemplatePatron ÉtatPatron Composite3Propriétés de classe
Variables d'instance vs variables de classeDécorateurs de propriétéAttributs privésRécapitulatif - Gestionnaire de compte bancaireEntraînez-vous par vous-même : Compilateur Python en ligne