Patron État
Fait partie de la section Object Oriented Programming du Journey Python de Coddy — leçon 53 sur 64.
Le patron d'état (State Pattern) 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 des classes d'état simples pour un feu de signalisation :
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() # Commencer par le rouge
def change(self):
self.state.next_state(self)
def get_color(self):
return self.state.current_color()Le feu de signalisation délègue le comportement à son objet d'état actuel.
Utilisez le feu de signalisation :
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 cours de 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 State Pattern encapsule le comportement spécifique à l'état dans des classes séparées et laisse l'objet contexte 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
FacileDans ce défi, vous implémenterez la classe State dans state.py avec une encapsulation et des méthodes appropriées. Le fichier contient des commentaires TODO détaillés pour guider votre implémentation étape par étape.
La suite de tests est conçue pour vérifier que votre implémentation répond à toutes les exigences et gère correctement les conditions exceptionnelles. Utilisez les résultats des tests pour comprendre le comportement attendu et affiner votre solution.
Aide-mémoire
Le patron d'état (State Pattern) permet à un objet de modifier son comportement lorsque son état interne change. L'objet semble changer de classe en fonction de son état actuel.
Créez des classes d'état qui définissent le comportement pour chaque état :
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"Créez une classe de contexte qui détient l'état actuel :
class TrafficLight:
def __init__(self):
self.state = RedState() # Commencer par le rouge
def change(self):
self.state.next_state(self)
def get_color(self):
return self.state.current_color()Exemple d'utilisation :
light = TrafficLight()
print(f"Current: {light.get_color()}") # Actuel : Red
light.change() # Red -> Green
print(f"Current: {light.get_color()}") # Actuel : GreenLe patron d'état encapsule le comportement spécifique à l'état dans des classes séparées et laisse l'objet de contexte déléguer à l'état actuel. Cela élimine les instructions if/else complexes et facilite l'ajout de nouveaux états.
Essayez vous-même
from state import State
# Gestionnaire de cas de test complet
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")
# Accès direct à l'attribut privé (non recommandé)
print(f"Direct access (not recommended): {obj._name}")
# Accès via la propriété (recommandé)
print(f"Property access (recommended): {obj.name}")
elif test_case == "property_behavior_test":
obj = State("Original Name")
print(f"Original name: {obj.name}")
# Tenter de modifier le nom (échouera car il n'y a pas de setter)
try:
obj.name = "New Name"
except AttributeError as e:
print(f"Error when trying to modify name: {e}")
# Montrer que le nom est inchangé
print(f"Name after modification attempt: {obj.name}")Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Object Oriented Programming
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 bancaire