Event Bus e padrão Observer em Go (Golang): 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 Go (Golang)



No mundo do desenvolvimento moderno em Go (Golang), surge frequentemente a necessidade de organizar uma interação fracamente acoplada entre os componentes da aplicação. Duas abordagens clássicas são o padrão Observer e sua implementação mais avançada — o Event Bus (barramento de eventos). Esses mecanismos permitem que partes do programa reajam às ações de outras, sem criar dependências rígidas.



Neste artigo, vamos analisar como implementar um Event Bus em Go puro, sem dependências externas, examinar o padrão Observer e mostrar exemplos de código para processamento síncrono e assíncrono de eventos.



O que é o padrão Observer?



O padrão Observer (Observador) é um padrão de design comportamental que cria um mecanismo de inscrição, permitindo que objetos acompanhem e reajam a eventos que ocorrem em outros objetos.



Elementos principais:

  • Subject (Sujeito) — objeto que gera eventos.
  • Observer (Observador) — objeto que se inscreve nos eventos.
  • Event (Evento) — dados transmitidos do sujeito aos observadores.


O que é Event Bus?



Event Bus é um barramento centralizado que gerencia a transmissão de eventos entre publicadores (publishers) e assinantes (subscribers). Diferente do Observer clássico, onde o sujeito armazena diretamente a lista de observadores, o Event Bus atua como intermediário. Isso torna o sistema ainda mais flexível e escalável.



Implementação de Event Bus em Go



Go não possui uma implementação nativa de Event Bus, mas pode ser facilmente criado usando goroutines, canais e interfaces. Vamos considerar uma implementação simples, porém completa.



1. Definindo tipos básicos



// Event representa a estrutura do eventotype Event struct {    Name string    Data interface{}}

// EventHandler — função manipuladora de eventostype EventHandler func(Event)


2. Criando o Event Bus



type EventBus struct {    handlers map[string][]EventHandler    mu       sync.RWMutex}

// NewEventBus cria um novo barramento de eventosfunc NewEventBus() *EventBus { return &EventBus{ handlers: make(map[string][]EventHandler), }}

// Subscribe inscreve um manipulador em um eventofunc (eb *EventBus) Subscribe(name string, handler EventHandler) { eb.mu.Lock() defer eb.mu.Unlock() eb.handlers[name] = append(eb.handlers[name], handler)}

// Publish publica um evento de forma síncronafunc (eb *EventBus) Publish(name string, data interface{}) { eb.mu.RLock() defer eb.mu.RUnlock() if handlers, ok := eb.handlers[name]; ok { event := Event{Name: name, Data: data} for _, handler := range handlers { handler(event) } }}


3. Publicação assíncrona



Para processamento assíncrono, podemos executar cada manipulador em uma goroutine separada:



// PublishAsync publica um evento de forma assíncronafunc (eb *EventBus) PublishAsync(name string, data interface{}) {    eb.mu.RLock()    defer eb.mu.RUnlock()    if handlers, ok := eb.handlers[name]; ok {        event := Event{Name: name, Data: data}        for _, handler := range handlers {            go handler(event)        }    }}


Exemplo de uso



Vamos ver como usar nosso Event Bus em uma aplicação real. Suponha que temos um sistema que registra ações do usuário e envia notificações.



func main() {    bus := NewEventBus()

// Inscrevendo-se no evento "user.login" bus.Subscribe("user.login", func(e Event) { userData := e.Data.(map[string]string) fmt.Printf("Log: Usuário %s fez login", userData["username"]) })

// Inscrevendo-se no mesmo evento para en

Recommendations