Pattern État
Fait partie de la section Programmation Orientée Objet du Journey C++ de Coddy. Leçon 100 sur 104.
Le pattern State permet à un objet de modifier son comportement lorsque son état interne change, donnant l’impression que l’objet a changé de classe. Au lieu d’utiliser des instructions conditionnelles complexes pour gérer différents états, vous encapsulez chaque état dans une classe distincte.
Le modèle se compose d’un Contexte qui conserve une référence vers l’état actuel, d’une interface d’état qui définit le comportement propre à chaque état, et d’États concrets qui implémentent le comportement de chaque état :
#include <iostream>
#include <memory>
class Document; // Déclaration anticipée
// Interface d'état
class DocumentState {
public:
virtual void publish(Document& doc) = 0;
virtual std::string getName() const = 0;
virtual ~DocumentState() = default;
};
// Contexte
class Document {
std::unique_ptr<DocumentState> state;
public:
Document();
void setState(std::unique_ptr<DocumentState> newState) {
state = std::move(newState);
}
void publish() { state->publish(*this); }
std::string getStateName() const { return state->getName(); }
};
// États concrets
class Draft : public DocumentState {
public:
void publish(Document& doc) override;
std::string getName() const override { return "Draft"; }
};
class Review : public DocumentState {
public:
void publish(Document& doc) override;
std::string getName() const override { return "Review"; }
};
class Published : public DocumentState {
public:
void publish(Document& doc) override {
std::cout << "Already published\n";
}
std::string getName() const override { return "Published"; }
};
void Draft::publish(Document& doc) {
std::cout << "Moving to review\n";
doc.setState(std::make_unique<Review>());
}
void Review::publish(Document& doc) {
std::cout << "Publishing document\n";
doc.setState(std::make_unique<Published>());
}
Document::Document() : state(std::make_unique<Draft>()) {}Chaque état gère l’action publish() différemment et est chargé de passer à l’état suivant. Le Document n’a pas besoin de connaître la logique de transition : il la délègue simplement à l’état actuel. Cela élimine les grandes instructions switch et facilite l’ajout de nouveaux états.
Utilisez State lorsque le comportement d’un objet dépend fortement de son état et que vous avez de nombreuses instructions conditionnelles qui basculent selon l’état de l’objet.
Défi
FacileConstruisons un contrôleur de feu de signalisation à l’aide du pattern State. Vous allez créer un système dans lequel un feu de signalisation parcourt différents états (Red, Yellow, Green), chaque état déterminant ce qui se passe lorsque le feu change et quel message est affiché. Il s’agit d’un exemple classique du pattern State : le comportement du feu de signalisation dépend entièrement de son état actuel.
Vous allez organiser votre code sur trois fichiers :
TrafficLightState.h: définir l’interface d’état et toutes les classes d’état concrètes.Créez une classe abstraite
TrafficLightStateavec :- Une méthode virtuelle pure
change(TrafficLight& light)qui gère la transition vers l’état suivant - Une méthode virtuelle pure
getColor()qui renvoie la couleur actuelle sous forme de chaîne - Une méthode virtuelle pure
getAction()qui renvoie ce que les conducteurs doivent faire (par exemple, "Stop", "Caution", "Go") - Un destructeur virtuel
Implémentez trois états concrets :
RedState: la couleur est"Red", l’action est"Stop", et l’état change vers GreenYellowState: la couleur est"Yellow", l’action est"Caution", et l’état change vers RedGreenState: la couleur est"Green", l’action est"Go", et l’état change vers Yellow
Vous aurez besoin d’une déclaration anticipée de
TrafficLight, puisque les états y font référence.- Une méthode virtuelle pure
TrafficLight.h: créer la classe de contexte qui conserve l’état actuel.Votre classe
TrafficLightdoit contenir unstd::unique_ptr<TrafficLightState>et commencer par défaut dans l’état Red. Implémentez :setState(std::unique_ptr<TrafficLightState> newState): change l’état actuelchange(): délègue la transition à la méthode change de l’état actueldisplay(): affiche l’état du feu au format :[Color]: [Action]
main.cpp: démontrer le cycle du feu de signalisation à travers ses états.Lisez une entrée : le nombre de changements d’état à effectuer (un entier).
Créez un
TrafficLightet affichez son état initial. Effectuez ensuite le nombre de changements spécifié, en affichant l’état après chaque changement.
Par exemple, avec l’entrée 3 :
Red: Stop
Green: Go
Yellow: Caution
Red: StopAvec l’entrée 6 :
Red: Stop
Green: Go
Yellow: Caution
Red: Stop
Green: Go
Yellow: Caution
Red: StopRemarquez comment le feu de signalisation parcourt ses états selon un schéma prévisible : Red → Green → Yellow → Red. Chaque état sait quel état vient ensuite et gère sa propre transition. La classe TrafficLight n’a besoin d’aucune logique conditionnelle pour déterminer ce qui se passe. Elle délègue simplement la tâche à l’état dans lequel elle se trouve actuellement.
Essayez vous-même
#include <iostream>
#include "TrafficLight.h"
using namespace std;
int main() {
// Lire le nombre de changements d'état
int numChanges;
cin >> numChanges;
// TODO: Créer un objet TrafficLight
// TODO: Afficher l'état initial
// TODO: Effectuer le nombre spécifié de changements
// Après chaque changement, afficher l'état actuel
return 0;
}
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
1Fondamentaux de la POO
Fichiers externesGénération et compilation en C++Fichiers d’en-tête et fichiers sourceEspaces de noms et portéeIntroduction à la POO en C++Classes et objetsLe pointeur « this »Méthodes (fonctions membres)Attributs (membres de données)Bases des constructeurs et destructeursRécapitulatif - Calculatrice simple4Propriétés de classe
Membres d’instance et statiquesAccesseurs et mutateursFonctions membres constMot-clé mutableMéthodes et variables statiquesFonctions et classes amiesRécapitulatif - Gestionnaire de compte bancaire7Héritage
Héritage de baseNiveaux d’accès de l’héritageOrdre d’appel des constructeurs et destructeursRedéfinition des méthodesFonctions virtuelles et VTableHéritage multipleHéritage virtuelRécapitulatif : hiérarchie des employés10Vue d’ensemble de la STL
Vue d’ensemble et philosophie de la STLConteneurs de la STLItérateursAlgorithmes de la STLFoncteurs et expressions lambdaRécapitulatif - fréquence des mots13Modèles de conception, partie 1
Introduction aux modèles de conceptionModèle SingletonFabrique et fabrique abstraiteModèle BuilderModèle ObserverModèle Strategy2Gestion de la mémoire
Mémoire de pile ou de tasPointeurs et référencesMémoire dynamique (new/delete)Pointeurs intelligents en C++RAII en C++Récapitulatif - Gestionnaire de tableaux dynamiques5Encapsulation
Spécificateurs d’accès en C++Spécificateurs d’accès en profondeurMasquage de l’informationStruct vs classeClasses imbriquées et internesRécapitulatif - Système de gestion des dossiers étudiants8Polymorphisme
Polymorphisme à la compilation vs à l’exécutionSurcharge de fonctionsRetour sur les fonctions virtuellesFonctions virtuelles puresClasses abstraitesConception d’interfaces en C++Conversion dynamique et RTTIRécapitulatif - Calculateur de formes11Concepts avancés de la POO
Composition ou héritageMixins via CRTPIdiom PimplEffacement de typeClasses enum et typage fortGestion des exceptions en POOHiérarchies d’exceptions personnalisées14Design Patterns – Partie 2
Pattern CommandePattern AdaptateurPattern DécorateurPattern Méthode ModèlePattern ÉtatPattern CompositeRAII comme Pattern3Constructeurs et destructeurs
Constructeur par défautConstructeur paramétréConstructeur de copieConstructeur de déplacementListes d’initialisation des constructeursConstructeurs déléguésApprofondissement des destructeursRègle des trois / cinq / zéroRécapitulatif - Classe String6Surcharge des opérateurs
Introduction à la surcharge des opérateursSurcharge des opérateurs arithmétiquesSurcharge des opérateurs de comparaisonOpérateurs de fluxSurcharge de l’opérateur d’affectationSurcharge des opérateurs [] et ()Opérateurs de conversion de typeRécapitulatif – Classe Matrix9Templates
Templates de fonctionsTemplates de classesSpécialisation des templatesTemplates variadiquesBases de SFINAE et des traits de typesRécapitulatif - Conteneur génériqueEntraînez-vous par vous-même : Compilateur C++ en ligne