Event Bus und Observer-Pattern in C++: Implementierung mit modernem C++

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Event Bus und Observer-Pattern in C++: Von der Theorie zur modernen Implementierung



In der modernen C++-Entwicklung entsteht immer häufiger der Bedarf an einem flexiblen Mechanismus zum Nachrichtenaustausch zwischen Komponenten, die nicht direkt voneinander wissen sollen. Das Observer-Pattern und seine Weiterentwicklung – der Event Bus – lösen diese Aufgabe, indem sie lose gekoppelte, erweiterbare Systeme ermöglichen. In diesem Artikel analysieren wir, wie man einen Event Bus in C++ unter Verwendung der Standardbibliothek (C++17/20) implementiert, und betrachten praktische Beispiele.



Observer-Pattern: Die klassische Grundlage



Das Observer-Pattern definiert eine "Eins-zu-Vielen"-Beziehung zwischen Objekten: Wenn ein Objekt (Subjekt) seinen Zustand ändert, werden alle abhängigen Objekte (Beobachter) automatisch darüber benachrichtigt. In C++ sieht die klassische Implementierung so aus:



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

// Basisklasse des Beobachtersclass IObserver {public: virtual ~IObserver() = default; virtual void update(const std::string& message) = 0;};

// Subjekt (Herausgeber)class Subject {private: std::vector<std::weak_ptr<IObserver>> observers_;public: void attach(std::shared_ptr<IObserver> observer) { observers_.push_back(observer); }

void detach(std::shared_ptr<IObserver> observer) { observers_.erase( std::remove_if(observers_.begin(), observers_.end(), [&observer](const std::weak_ptr<IObserver>& wp) { auto sp = wp.lock(); return !sp || sp == observer; }), observers_.end() ); }

void notify(const std::string& message) { for (auto it = observers_.begin(); it != observers_.end(); ) { if (auto sp = it->lock()) { sp->update(message); ++it; } else { it = observers_.erase(it); // "tote" Referenzen entfernen } } }};

// Konkreter Beobachterclass ConcreteObserver : public IObserver {private: std::string name_;public: ConcreteObserver(const std::string& name) : name_(name) {} void update(const std::string& message) override { std::cout << "[" << name_ << "] erhalten: " << message << std::endl; }};

int main() { auto subject = std::make_shared<Subject>(); auto obs1 = std::make_shared<ConcreteObserver>("Beobachter 1"); auto obs2 = std::make_shared<ConcreteObserver>("Beobachter 2");

subject->attach(obs1); subject->attach(obs2); subject->notify("Ereignis eingetreten!");

subject->detach(obs1); subject->notify("Nur für den zweiten");

return 0;}


Dieser Code funktioniert, hat aber Einschränkungen: Alle Beobachter müssen von IObserver erben, und Nachrichten müssen Zeichenketten sein. In der Praxis wird ein flexibleres System benötigt.



Event Bus: Die moderne Weiterentwicklung



Ein Event Bus ist ein zentraler Bus, über den Komponenten Ereignisse veröffentlichen und abonnieren können. Die wesentlichen Unterschiede zum klassischen Observer:

  • Typisierte Ereignisse – jedes Ereignis hat seinen eigenen Datentyp.
  • Keine starre Hierarchie – Abonnenten müssen keine gemeinsame Schnittstelle erben.
  • Globaler oder lokaler Bus – man kann einen Event Bus für die gesamte Anwendung oder mehrere isolierte Busse haben.


Implementierung eines Event Bus in C++17/20 mit std::any



Wir verwenden std::any zum Speichern von Daten beliebigen Typs und std::function für die Handler. Zur Trennung der Ereignisse nach Typen nutzen wir std::type_index.



#include <iostream>#include <any>#include <function                    

Empfehlungen