Menu
Coddy logo textTech

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 stopped

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

challenge icon

Défi

Facile

Implé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é.

  • LampState est la classe de base avec press(lamp) et describe().
  • OffState, LowState et HighState les implémentent : press appelle lamp.set_state(...) avec l’état suivant (de éteinte à faible, de faible à forte, de forte à éteinte) et describe renvoie Lamp is off, Lamp is on low ou Lamp is on high.
  • Lamp est le contexte : il démarre dans OffState, set_state remplace l’objet représentant l’état, press_button délègue à l’état actuel, et status renvoie 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())
quiz iconTestez-vous

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

Entraînez-vous par vous-même : Compilateur Python en ligne