Event Bus e padrão Observer em Rust: implementação e exemplos

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Event Bus e padrão Observer em Rust: implementação e exemplos



Event Bus (barramento de eventos) é um padrão arquitetural que implementa o princípio publish-subscribe (publicador-assinante). Em Rust, esse padrão é especialmente útil para construir sistemas fracamente acoplados, onde os componentes se comunicam através de eventos sem se conhecerem diretamente. Neste artigo, vamos analisar como criar seu próprio Event Bus usando o padrão Observer e explorar soluções prontas do ecossistema Rust.



Padrão Observer: fundamentos



O padrão Observer define uma relação "um-para-muitos" entre objetos. Quando um objeto (publicador) altera seu estado, todos os objetos dependentes (assinantes) são automaticamente notificados. Em Rust, isso é frequentemente implementado através de traits e despacho dinâmico.



Implementação básica do Observer em Rust



use std::collections::HashMap;

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

// Estrutura do 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 recebido: {}", event); }}

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


Event Bus: versão estendida do Observer



Event Bus é um barramento centralizado que roteia eventos por tipo. Diferente do Observer simples, aqui são suportados diferentes tipos de eventos e filtragem de assinaturas.



Implementação do Event Bus com 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,}

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

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

// Barramento 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!("Usuário entrou: {}", event.payload); });

bus.subscribe(EventType::UserLogin, |event| { // Outro manipulador println!("Login registrado: {}", event.payload); });

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


Event Bus assíncrono com Tokio



Em aplicações reais, frequentemente é necessário o processamento assíncrono de eventos. Para isso, a biblioteca tokio com seus canais broadcast é excelente.



Uso de tokio::sync::broadcast



use tokio::sync::broadcast;

#[tokio::main]async fn m

Recommendations