Menu
Coddy logo textTech

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.

challenge icon

Défi

Facile

Construisons 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 TrafficLightState avec :

    • 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 Green
    • YellowState : la couleur est "Yellow", l’action est "Caution", et l’état change vers Red
    • GreenState : 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.

  • TrafficLight.h : créer la classe de contexte qui conserve l’état actuel.

    Votre classe TrafficLight doit contenir un std::unique_ptr<TrafficLightState> et commencer par défaut dans l’état Red. Implémentez :

    • setState(std::unique_ptr<TrafficLightState> newState) : change l’état actuel
    • change() : délègue la transition à la méthode change de l’état actuel
    • display() : 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 TrafficLight et 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: Stop

Avec l’entrée 6 :

Red: Stop
Green: Go
Yellow: Caution
Red: Stop
Green: Go
Yellow: Caution
Red: Stop

Remarquez 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;
}
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 C++ en ligne