Menu
Coddy logo textTech

Patron Observateur

Fait partie de la section Programmation Orientée Objet du Journey C++ de Coddy — leçon 94 sur 104.

Le patron de conception Observateur définit une dépendance de type un-à-plusieurs entre des objets : lorsqu'un objet (le sujet) change d'état, tous ses dépendants (les observateurs) sont notifiés automatiquement. C'est idéal pour les systèmes d'événements, les mises à jour d'interface utilisateur (UI), ou tout scénario où plusieurs objets doivent réagir à des changements.

Le patron implique deux rôles clés : un Subject qui maintient une liste d'observateurs et les notifie, et des Observers qui implémentent une interface de mise à jour :

#include <iostream>
#include <vector>
#include <algorithm>

class Observer {
public:
    virtual void update(int value) = 0;
    virtual ~Observer() = default;
};

class Subject {
    std::vector<Observer*> observers;
    int state = 0;
    
public:
    void attach(Observer* obs) {
        observers.push_back(obs);
    }
    
    void detach(Observer* obs) {
        observers.erase(
            std::remove(observers.begin(), observers.end(), obs),
            observers.end());
    }
    
    void setState(int value) {
        state = value;
        notify();
    }
    
    void notify() {
        for (Observer* obs : observers) {
            obs->update(state);
        }
    }
};

class Display : public Observer {
    std::string name;
public:
    Display(const std::string& n) : name(n) {}
    void update(int value) override {
        std::cout << name << " received: " << value << "\n";
    }
};

int main() {
    Subject sensor;
    Display screen1("Screen1"), screen2("Screen2");
    
    sensor.attach(&screen1);
    sensor.attach(&screen2);
    sensor.setState(42);  // Les deux afficheurs sont notifiés
}

Lorsque setState() est appelé, le sujet parcourt tous les observateurs enregistrés et appelle leur méthode update(). Les observateurs peuvent s'attacher ou se détacher à tout moment, ce qui rend le système flexible et faiblement couplé.

Utilisez le pattern Observateur lorsque les modifications apportées à un objet nécessitent la mise à jour d'autres objets, et que vous ne voulez pas que ces objets soient fortement couplés entre eux.

challenge icon

Défi

Facile

Construisons un système de surveillance de Station Météo en utilisant le patron de conception Observer (Observateur). Vous allez créer une station météo qui suit les données de température et informe automatiquement plusieurs unités d'affichage chaque fois que la température change — une application concrète et classique de ce patron.

Vous organiserez votre code sur trois fichiers :

  • Observer.h : Définissez l'interface de l'observateur et un observateur d'affichage concret.

    Créez une classe abstraite Observer avec une méthode virtuelle pure update(double temperature) que les observateurs implémentent pour recevoir les notifications, ainsi qu'un destructeur virtuel.

    Ensuite, créez une classe TemperatureDisplay qui hérite de Observer. Chaque affichage possède un nom (string) défini via son constructeur. Lorsque update() est appelée, elle doit afficher :

    [DisplayName]: Temperature is [temperature] degrees
  • WeatherStation.h : Créez le sujet qui maintient la température et notifie les observateurs.

    Votre classe WeatherStation doit :

    • Stocker une liste de pointeurs d'observateurs et la température actuelle (initialisée à 0.0)
    • Avoir une méthode attach(Observer* obs) pour enregistrer les observateurs
    • Avoir une méthode detach(Observer* obs) pour supprimer les observateurs
    • Avoir une méthode setTemperature(double temp) qui met à jour la température et notifie tous les observateurs attachés
    • Avoir une méthode privée notify() qui appelle update() sur chaque observateur avec la température actuelle
  • main.cpp : Démontrez le patron Observer en action.

    Lisez trois entrées :

    1. Le nom du premier affichage (string)
    2. Le nom du deuxième affichage (string)
    3. Une valeur de température (double)

    Créez une WeatherStation et deux objets TemperatureDisplay avec les noms fournis. Attachez les deux affichages à la station, puis réglez la température sur la valeur d'entrée. Les deux affichages doivent automatiquement recevoir la mise à jour et afficher leurs messages.

    Après cela, détachez le premier affichage et réglez une nouvelle température supérieure de 5 degrés à l'entrée. Seul le deuxième affichage doit recevoir cette mise à jour.

Par exemple, avec les entrées Kitchen, Bedroom, et 22.5 :

Kitchen: Temperature is 22.5 degrees
Bedroom: Temperature is 22.5 degrees
Bedroom: Temperature is 27.5 degrees

Avec les entrées Office, Lobby, et 18.0 :

Office: Temperature is 18 degrees
Lobby: Temperature is 18 degrees
Lobby: Temperature is 23 degrees

Remarquez comment le patron Observer crée un système à couplage faible — la station météo n'a pas besoin de connaître les détails des affichages spécifiques, elle informe simplement quiconque est à l'écoute. Lorsque vous détachez un observateur, il cesse automatiquement de recevoir les mises à jour.

Aide-mémoire

Le patron de conception Observateur (Observer pattern) définit une dépendance de un à plusieurs où un sujet notifie automatiquement tous ses observateurs lorsque son état change.

Le patron comporte deux rôles clés :

  • Sujet (Subject) : Maintient une liste d'observateurs et les informe des changements d'état
  • Observateur (Observer) : Implémente une interface de mise à jour pour recevoir les notifications

Implémentation de base :

#include <iostream>
#include <vector>
#include <algorithm>

class Observer {
public:
    virtual void update(int value) = 0;
    virtual ~Observer() = default;
};

class Subject {
    std::vector<Observer*> observers;
    int state = 0;
    
public:
    void attach(Observer* obs) {
        observers.push_back(obs);
    }
    
    void detach(Observer* obs) {
        observers.erase(
            std::remove(observers.begin(), observers.end(), obs),
            observers.end());
    }
    
    void setState(int value) {
        state = value;
        notify();
    }
    
    void notify() {
        for (Observer* obs : observers) {
            obs->update(state);
        }
    }
};

class Display : public Observer {
    std::string name;
public:
    Display(const std::string& n) : name(n) {}
    void update(int value) override {
        std::cout << name << " received: " << value << "\n";
    }
};

Méthodes clés :

  • attach() : Enregistre un observateur pour recevoir des notifications
  • detach() : Supprime un observateur de la liste de notification
  • notify() : Parcourt tous les observateurs et appelle leur méthode update()

Utilisez le patron Observateur lorsque les modifications apportées à un objet nécessitent la mise à jour d'autres objets sans couplage fort entre eux.

Essayez vous-même

#include <iostream>
#include <string>
#include "WeatherStation.h"

using namespace std;

int main() {
    // Lire les entrées
    string display1Name, display2Name;
    double temperature;
    
    cin >> display1Name;
    cin >> display2Name;
    cin >> temperature;
    
    // TODO: Créer un objet WeatherStation
    
    // TODO: Créer deux objets TemperatureDisplay avec les noms saisis
    
    // TODO: Attacher les deux afficheurs à la WeatherStation
    
    // TODO: Régler la température à la valeur saisie
    // (Les deux afficheurs doivent imprimer leurs messages)
    
    // TODO: Détacher le premier afficheur
    
    // TODO: Régler la température à 5 degrés de plus que la valeur saisie
    // (Seul le deuxième afficheur doit imprimer)
    
    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