Event Bus et le pattern Observer en C++ : de la théorie à la pratique
\n\nDans le développement logiciel moderne en C++, le faible couplage des composants joue un rôle important. Le pattern Observer (Observateur) et son évolution — l'Event Bus (Bus d'événements) — offrent un mécanisme élégant pour organiser l'interaction entre objets sans créer de dépendances rigides. Dans cet article, nous analyserons en détail comment implémenter ces patterns en C++, examinerons leurs avantages et limites, et fournirons des exemples pratiques de code.
\n\nPattern Observer : implémentation classique
\n\nLe pattern Observer définit une relation "un à plusieurs" entre objets : lorsqu'un objet (sujet) modifie son état, tous les objets qui en dépendent (observateurs) en sont automatiquement notifiés. En C++, l'implémentation classique se présente comme suit :
\n\n#include <iostream>\n#include <vector>\n#include <memory>\n#include <algorithm>\n\n// Interface de l'observateur\nclass IObserver {\npublic:\n virtual ~IObserver() = default;\n virtual void update(const std::string& message) = 0;\n};\n\n// Observateur concret\nclass ConcreteObserver : public IObserver {\nprivate:\n std::string name;\npublic:\n explicit ConcreteObserver(const std::string& n) : name(n) {}\n void update(const std::string& message) override {\n std::cout << "[" << name << "] Reçu : " << message << std::endl;\n }\n};\n\n// Sujet (objet observé)\nclass Subject {\nprivate:\n std::vector<std::shared_ptr<IObserver>> observers;\n std::string state;\npublic:\n void attach(std::shared_ptr<IObserver> observer) {\n observers.push_back(observer);\n }\n void detach(std::shared_ptr<IObserver> observer) {\n observers.erase(\n std::remove(observers.begin(), observers.end(), observer),\n observers.end()\n );\n }\n void notify() {\n for (auto& observer : observers) {\n observer->update(state);\n }\n }\n void setState(const std::string& newState) {\n state = newState;\n notify();\n }\n};\n\nint main() {\n Subject subject;\n auto obs1 = std::make_shared<ConcreteObserver>("Observateur 1");\n auto obs2 = std::make_shared<ConcreteObserver>("Observateur 2");\n \n subject.attach(obs1);\n subject.attach(obs2);\n \n subject.setState("Événement #1 s'est produit !");\n subject.detach(obs1);\n subject.setState("Événement #2 sans le premier observateur");\n \n return 0;\n}\n\nEvent Bus : bus d'événements centralisé
\n\nL'Event Bus étend l'idée de l'Observer en fournissant un mécanisme centralisé d'échange de messages. Au lieu que chaque sujet stocke une liste d'observateurs, tous les abonnements et publications passent par un bus unique. Cela permet de :
\n- \n
- Réduire le couplage — les émetteurs et les récepteurs ne se connaissent pas mutuellement. \n
- Simplifier la mise à l'échelle — de nouveaux types d'événements sont ajoutés sans modifier le code existant. \n
- Assurer la flexibilité — il est possible d'ajouter et de supprimer des abonnés à l'exécution. \n
Exemple d'implémentation d'un Event Bus en C++ utilisant des templates et std::function :
\n\n#include <iostream>\n#include <unordered_map>\n#include <functional>\n#include <any>\n#include <typeindex>\n#include <vector>\n#include <memory>\n\n// Classe de base pour les événements\nstruct Event {\n virtual ~Event() = default;\n};\n\n// Événement concret\nstruct UserLoginEvent : public Event {\n std::string username;\n explicit UserLoginEvent(std::string name) : username(std::move(name)) {}\n};\n\n// Classe Event Bus\nclass EventBus {\nprivate:\n std::unordered_map<std::type_index, std::vector<std::function<void(const std::any&)>>> hand Aussi dans la bibliothèque
Migrations de bases de données dans Node.js : Sequelize, Knex et TypeORM
Client HTTP pour Java : top bibliothèques pour travailler avec HTTP
Detekt pour Kotlin : guide complet avec exemples
Planificateur de tâches Java : Quartz Scheduler — guide complet