// C / C++

Le design pattern Observer en C++

Le pattern Observer (parfois appelé observateur/observable, ou publish-subscribe dans sa forme étendue) répond à une question omniprésente : comment prévenir plusieurs objets qu’un état a changé, sans les coupler fortement entre eux ? C’est le mécanisme derrière les interfaces réactives, les systèmes d’événements et une bonne partie du code UI.

Le principe

Un sujet (observable) maintient une liste d’observateurs. Quand son état change, il les notifie tous en appelant une méthode convenue. Les observateurs n’ont pas besoin de se connaître, et le sujet ne connaît que l’interface abstraite Observateur — pas les classes concrètes. Couplage minimal, extension facile.

Implémentation en C++ moderne

#include <vector>
#include <memory>
#include <iostream>

class Observateur {
public:
    virtual void notifier(int valeur) = 0;
    virtual ~Observateur() = default;
};

class Sujet {
    std::vector<std::weak_ptr<Observateur>> observateurs_;
    int etat_ = 0;
public:
    void abonner(std::shared_ptr<Observateur> o) {
        observateurs_.push_back(o);
    }
    void setEtat(int v) {
        etat_ = v;
        for (auto& faible : observateurs_)
            if (auto obs = faible.lock())  // l'observateur existe-t-il encore ?
                obs->notifier(etat_);
    }
};

Point crucial : on stocke des std::weak_ptr, pas des shared_ptr. Pourquoi ? Si le sujet gardait des shared_ptr, il empêcherait la destruction de ses observateurs (référence circulaire, fuite mémoire). Le weak_ptr permet de vérifier, via lock(), si l’observateur est encore vivant avant de le notifier. C’est l’un des pièges classiques de l’Observer en C++.

Utilisation

class Afficheur : public Observateur {
public:
    void notifier(int v) override {
        std::cout << "Nouvel état : " << v << "\n";
    }
};

Sujet capteur;
auto ecran = std::make_shared<Afficheur>();
capteur.abonner(ecran);
capteur.setEtat(42);   // affiche "Nouvel état : 42"

Alternatives modernes

En C++ contemporain, on remplace souvent une interface d’observateur par des callbacks stockés dans des std::function, ce qui évite d’imposer l’héritage. Pour des besoins de réactivité plus poussés (flux d’événements composables), on se tourne vers des bibliothèques de programmation réactive. Mais pour comprendre le mécanisme, l’implémentation classique reste la meilleure école.


L’Observer complète bien le pattern Factory dans une architecture propre. Pour gérer sans fuite les shared_ptr et weak_ptr évoqués ici, lisez notre guide RAII en C++. Et si vous débutez, (re)voyez d’abord les fondamentaux du langage C.