Event Bus und das Observer-Muster in C++: Implementierung und Beispiele

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 das Observer-Muster in C++: Von der Theorie zur Praxis

\n\n

In der modernen Softwareentwicklung mit C++ spielt die lose Kopplung von Komponenten eine wichtige Rolle. Das Observer-Muster (Beobachter) und seine Weiterentwicklung – der Event Bus (Ereignisbus) – bieten einen eleganten Mechanismus zur Organisation der Interaktion zwischen Objekten, ohne starre Abhängigkeiten zu schaffen. In diesem Artikel werden wir detailliert erläutern, wie diese Muster in C++ implementiert werden, ihre Vorteile und Einschränkungen betrachten sowie praktische Codebeispiele liefern.

\n\n

Observer-Muster: Klassische Implementierung

\n\n

Das Observer-Muster definiert eine "Eins-zu-Viele"-Beziehung zwischen Objekten: Wenn ein Objekt (Subjekt) seinen Zustand ändert, werden alle von ihm abhängigen Objekte (Beobachter) automatisch benachrichtigt. In C++ sieht die klassische Implementierung wie folgt aus:

\n\n
#include <iostream>\n#include <vector>\n#include <memory>\n#include <algorithm>\n\n// Schnittstelle des Beobachters\nclass IObserver {\npublic:\n    virtual ~IObserver() = default;\n    virtual void update(const std::string& message) = 0;\n};\n\n// Konkreter Beobachter\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 << "] Empfangen: " << message << std::endl;\n    }\n};\n\n// Subjekt (beobachtetes Objekt)\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>("Beobachter 1");\n    auto obs2 = std::make_shared<ConcreteObserver>("Beobachter 2");\n    \n    subject.attach(obs1);\n    subject.attach(obs2);\n    \n    subject.setState("Ereignis #1 ist eingetreten!");\n    subject.detach(obs1);\n    subject.setState("Ereignis #2 ohne ersten Beobachter");\n    \n    return 0;\n}
\n\n

Event Bus: Zentrale Ereignisbus

\n\n

Der Event Bus erweitert die Idee des Observer-Musters, indem er einen zentralen Mechanismus für den Nachrichtenaustausch bereitstellt. Anstatt dass jedes Subjekt eine Liste von Beobachtern speichert, erfolgen alle Abonnements und Veröffentlichungen über einen einzigen Bus. Dies ermöglicht:

\n
    \n
  • Geringere Kopplung – Sender und Empfänger wissen nichts voneinander.
  • \n
  • Einfachere Skalierbarkeit – neue Ereignistypen werden hinzugefügt, ohne vorhandenen Code zu ändern.
  • \n
  • Flexibilität – Abonnenten können zur Laufzeit hinzugefügt und entfernt werden.
  • \n
\n\n

Beispiel einer Event Bus-Implementierung in C++ mit Templates und 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// Basisklasse für Ereignisse\nstruct Event {\n    virtual ~Event() = default;\n};\n\n// Konkretes Ereignis\nstruct UserLoginEvent : public Event {\n    std::string username;\n    explicit UserLoginEvent(std::string name) : username(std::move(name)) {}\n};\n\n// Event Bus-Klasse\nclass EventBus {\nprivate:\n    std::unordered_map<std::type_index, std::vector<std::function<void(const std::any&)>>> hand                    

Empfehlungen