Event Bus e padrão Observer em Rust: construindo uma arquitetura flexível orientada a eventos
No desenvolvimento moderno de software, surge frequentemente a necessidade de baixo acoplamento entre componentes. O padrão Observer e sua implementação prática — Event Bus (barramento de eventos) — permitem organizar uma interação eficiente entre módulos sem dependências diretas. Rust, com seu sistema de tipos rigoroso e foco em segurança, oferece excelentes oportunidades para implementar esse padrão. Neste artigo, vamos explorar como construir seu próprio Event Bus em Rust, utilizando os recursos nativos da linguagem e crates populares.
O que é Event Bus e o padrão Observer?
Padrão Observer define uma relação "um para muitos" entre objetos: quando um objeto (publicador) muda seu estado, todos os objetos dependentes (assinantes) são notificados automaticamente. Event Bus é um barramento centralizado que gerencia inscrições e distribuição de eventos, permitindo que qualquer componente publique eventos e se inscreva neles.
Principais vantagens:
- Baixo acoplamento: publicadores e assinantes não se conhecem diretamente
- Escalabilidade: fácil adicionar novos assinantes sem alterar o código existente
- Testabilidade: é possível testar componentes isoladamente, simulando eventos
- Assincronicidade: eventos podem ser processados em segundo plano
Implementação básica do Event Bus em Rust
Vamos começar com uma implementação síncrona simples, usando recursos padrão do Rust. A base será um HashMap, onde a chave é o tipo do evento e o valor é uma lista de manipuladores.
use std::collections::HashMap;use std::any::{Any, TypeId};use std::marker::PhantomData;
// Tipo de evento com identificador únicopub trait Event: Any + Clone + Send + 'static { fn event_type(&self) -> TypeId { TypeId::of::<Self>() }}
// Manipulador de eventopub trait EventHandler<E: Event>: Send + 'static { fn handle(&self, event: &E);}
// O barramento de eventospub struct EventBus { handlers: HashMap<TypeId, Vec<Box<dyn Any>>>,}
impl EventBus { pub fn new() -> Self { EventBus { handlers: HashMap::new(), } }
pub fn subscribe<E: Event, H: EventHandler<E>>(&mut self, handler: H) { let type_id = TypeId::of::<E>(); let boxed_handler = Box::new(handler) as Box<dyn Any>; self.handlers.entry(type_id).or_insert(Vec::new()).push(boxed_handler); }
pub fn publish<E: Event>(&self, event: &E) { let type_id = event.event_type(); if let Some(handlers) = self.handlers.get(&type_id) { for handler in handlers { if let Some(typed_handler) = handler.downcast_ref::<Box<dyn EventHandler<E>>>() { typed_handler.handle(event); } } } }}Exemplo de uso
// Definindo eventos#[derive(Clone)]struct UserLoggedIn { user_id: u32, username: String,}
impl Event for UserLoggedIn {}
#[derive(Clone)]struct DataUpdated { table: String, record_id: u64,}
impl Event for DataUpdated {}
// Definindo manipuladoresstruct Logger;impl EventHandler<UserLoggedIn> for Logger { fn handle(&self, event: &UserLoggedIn) { println!("[LOG] User {} (ID: {}) logged in", event.username, event.user_id); }}
struct EmailNotifier;impl EventHandler<UserLoggedIn> for EmailNotifier { fn handle(&self, event: &UserLoggedIn) { println!("[EMAIL] Sending welcome email to {}", event.username); }}
fn main() { le Também na biblioteca
Validação de dados em Rust: visão geral de bibliotecas e frameworks
Cliente Redis para C++: conexão, instalação e exemplos de uso
Aprendizado de Máquina em Kotlin: visão geral das bibliotecas KMath, Smile, KotlinDL e DeepLearning4J