Event Bus y el patrón Observer en Rust: implementación y ejemplos

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 el patrón Observer en Rust: implementación y ejemplos



Event Bus (bus de eventos) es un patrón arquitectónico que implementa el principio publish-subscribe (publicador-suscriptor). En Rust, este patrón es especialmente útil para construir sistemas débilmente acoplados, donde los componentes se comunican a través de eventos sin conocerse directamente. En este artículo, analizaremos cómo crear un Event Bus propio utilizando el patrón Observer y revisaremos soluciones listas del ecosistema de Rust.



Patrón Observer: fundamentos



El patrón Observer define una relación «uno-a-muchos» entre objetos. Cuando un objeto (publicador) cambia su estado, todos los objetos dependientes (suscriptores) son notificados automáticamente. En Rust, esto se implementa a menudo mediante traits y despacho dinámico.



Implementación básica de Observer en Rust



use std::collections::HashMap;

// Trait para el observadortrait Observer { fn update(&self, event: &str);}

// Estructura del publicadorstruct EventManager { observers: Vec<Box<dyn Observer>>,}

impl EventManager { fn new() -> Self { EventManager { observers: Vec::new(), } }

fn subscribe(&mut self, observer: Box<dyn Observer>) { self.observers.push(observer); }

fn notify(&self, event: &str) { for observer in &self.observers { observer.update(event); } }}

// Observador concretostruct Logger;

impl Observer for Logger { fn update(&self, event: &str) { println!("[Logger] Evento recibido: {}", event); }}

fn main() { let mut manager = EventManager::new(); manager.subscribe(Box::new(Logger)); manager.notify("user.login");}


Event Bus: versión extendida de Observer



Event Bus es un bus centralizado que enruta eventos por tipo. A diferencia del Observer simple, aquí se admiten diferentes tipos de eventos y filtrado de suscripciones.



Implementación de Event Bus con tipos de eventos



use std::any::Any;use std::collections::HashMap;use std::sync::{Arc, Mutex};

// Tipo de evento#[derive(Clone, Debug)]enum EventType { UserLogin, UserLogout, DataUpdate,}

// Estructura del evento#[derive(Clone, Debug)]struct Event { event_type: EventType, payload: String,}

// Manejador de eventostype Handler = Arc<dyn Fn(Event) + Send + Sync>;

// Bus de eventosstruct EventBus { handlers: HashMap<EventType, Vec<Handler>>,}

impl EventBus { fn new() -> Self { EventBus { handlers: HashMap::new(), } }

fn subscribe<F>(&mut self, event_type: EventType, handler: F) where F: Fn(Event) + 'static + Send + Sync, { self.handlers .entry(event_type) .or_insert_with(Vec::new) .push(Arc::new(handler)); }

fn publish(&self, event: Event) { if let Some(handlers) = self.handlers.get(&event.event_type) { for handler in handlers { handler(event.clone()); } } }}

fn main() { let mut bus = EventBus::new();

bus.subscribe(EventType::UserLogin, |event| { println!("Usuario inició sesión: {}", event.payload); });

bus.subscribe(EventType::UserLogin, |event| { // Otro manejador println!("Inicio de sesión registrado: {}", event.payload); });

bus.publish(Event { event_type: EventType::UserLogin, payload: "user123".to_string(), });}


Event Bus asíncrono con Tokio



En aplicaciones reales, a menudo se requiere procesamiento asíncrono de eventos. Para esto, la biblioteca tokio con sus canales broadcast es ideal.



Uso de tokio::sync::broadcast



use tokio::sync::broadcast;

#[tokio::main]async fn m

Recommendations