Modèle Observer
Fait partie de la section Programmation Orientée Objet du Journey C++ de Coddy. Leçon 94 sur 104.
Le pattern Observer définit une dépendance de type un-à-plusieurs entre les objets : lorsqu’un objet (le sujet) change d’état, tous ses dépendants (les observateurs) sont automatiquement avertis. Cela convient parfaitement aux systèmes d’événements, aux mises à jour de l’interface utilisateur ou à tout scénario dans lequel plusieurs objets doivent réagir aux changements.
Le modèle implique deux rôles clés : un Sujet qui gère une liste d’observateurs et les informe, et des Observateurs 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 affichages notifiés
}Lorsque setState() est appelée, 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 Observer lorsque des 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.
Défi
FacileConstruisons un système de surveillance de station météo utilisant le modèle Observer. Vous allez créer une station météo qui suit les données de température et avertit automatiquement plusieurs unités d’affichage chaque fois que la température change : une application classique de ce modèle dans le monde réel.
Vous organiserez votre code sur trois fichiers :
Observer.h: définir l’interface de l’observateur et un observateur d’affichage concret.Créez une classe abstraite
Observeravec une méthode virtuelle pureupdate(double temperature)que les observateurs implémentent pour recevoir les notifications, ainsi qu’un destructeur virtuel.Créez ensuite une classe
TemperatureDisplayqui hérite deObserver. Chaque affichage possède un nom (chaîne de caractères) défini par son constructeur. Lorsqueupdate()est appelée, elle doit afficher :[DisplayName]: Temperature is [temperature] degreesWeatherStation.h: créer le sujet qui conserve la température et avertit les observateurs.Votre classe
WeatherStationdoit :- Stocker une liste de pointeurs vers les observateurs ainsi que la température actuelle (initialisée à
0.0) - Posséder une méthode
attach(Observer* obs)pour enregistrer des observateurs - Posséder une méthode
detach(Observer* obs)pour supprimer des observateurs - Posséder une méthode
setTemperature(double temp)qui met à jour la température et avertit tous les observateurs associés - Posséder une méthode privée
notify()qui appelleupdate()sur chaque observateur avec la température actuelle
- Stocker une liste de pointeurs vers les observateurs ainsi que la température actuelle (initialisée à
main.cpp: démontrer le fonctionnement du modèle Observer.Lisez trois entrées :
- Nom du premier affichage (chaîne de caractères)
- Nom du deuxième affichage (chaîne de caractères)
- Une valeur de température (double)
Créez une
WeatherStationet deux objetsTemperatureDisplayavec les noms fournis. Associez les deux affichages à la station, puis définissez la température sur la valeur saisie. Les deux affichages doivent automatiquement recevoir la mise à jour et afficher leurs messages.Ensuite, détachez le premier affichage et définissez une nouvelle température supérieure de 5 degrés à la valeur saisie. 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 degreesAvec les entrées Office, Lobby et 18.0 :
Office: Temperature is 18 degrees
Lobby: Temperature is 18 degrees
Lobby: Temperature is 23 degreesRemarquez comment le modèle Observer crée un système faiblement couplé : la station météo n’a pas besoin de connaître les affichages spécifiques, elle avertit simplement toute personne à l’écoute. Lorsque vous détachez un observateur, celui-ci cesse automatiquement de recevoir les mises à jour.
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 d'entrée
// TODO: Attacher les deux affichages à la station météo
// TODO: Définir la température à la valeur d'entrée
// (Les deux affichages doivent imprimer leurs messages)
// TODO: Détacher le premier affichage
// TODO: Définir la température à 5 degrés de plus que l'entrée
// (Seul le second affichage doit imprimer)
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 formes3Constructeurs 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