Event Bus y patrón Observer en C++: implementación en C++ moderno

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Event Bus y patrón Observer en C++: de la teoría a la implementación moderna



En el desarrollo moderno con C++, cada vez surge más la necesidad de un mecanismo flexible para el intercambio de mensajes entre componentes que no deben conocerse directamente entre sí. El patrón Observer y su evolución — Event Bus — resuelven este problema, permitiendo construir sistemas débilmente acoplados y extensibles. En este artículo, analizaremos cómo implementar un Event Bus en C++ utilizando la biblioteca estándar (C++17/20) y veremos ejemplos prácticos.



Patrón Observer: la base clásica



El patrón Observer define una relación de "uno a muchos" entre objetos: cuando un objeto (sujeto) cambia su estado, todos los objetos dependientes (observadores) son notificados automáticamente. En C++, la implementación clásica se ve así:



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

// Clase base del observadorclass IObserver {public: virtual ~IObserver() = default; virtual void update(const std::string& message) = 0;};

// Sujeto (publicador)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); // eliminar referencias "muertas" } } }};

// Observador concretoclass 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_ << "] recibió: " << message << std::endl; }};

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

subject->attach(obs1); subject->attach(obs2); subject->notify("¡Ocurrió un evento!");

subject->detach(obs1); subject->notify("Solo para el segundo");

return 0;}


Este código funciona, pero tiene limitaciones: todos los observadores deben heredar de IObserver y los mensajes deben ser cadenas. En la práctica, se necesita un sistema más flexible.



Event Bus: evolución moderna



Event Bus es un bus centralizado a través del cual los componentes pueden publicar eventos y suscribirse a ellos. Diferencias clave con el Observer clásico:

  • Eventos tipificados — cada evento tiene su propio tipo de datos.
  • Sin jerarquía rígida — los suscriptores no están obligados a heredar una interfaz común.
  • Bus global o local — se puede tener un solo Event Bus para toda la aplicación o varios aislados.


Implementación de Event Bus en C++17/20 con std::any



Usamos std::any para almacenar datos de cualquier tipo y std::function para los manejadores. Para separar eventos por tipo, aplicamos std::type_index.



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

Recommendations