Event Bus und das Observer-Muster in Go (Golang): Implementierung und Beispiele

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Event Bus und das Observer-Muster in Go (Golang)



In der modernen Entwicklung mit Go (Golang) besteht häufig die Notwendigkeit, eine lose gekoppelte Interaktion zwischen den Komponenten einer Anwendung zu organisieren. Zwei klassische Ansätze sind das Observer-Muster und seine fortgeschrittenere Implementierung – der Event Bus (Ereignisbus). Diese Mechanismen ermöglichen es Teilen eines Programms, auf Aktionen anderer zu reagieren, ohne starre Abhängigkeiten zu schaffen.



In diesem Artikel werden wir erläutern, wie man einen Event Bus in reinem Go ohne externe Abhängigkeiten implementiert, das Observer-Muster betrachten und Codebeispiele für die synchrone und asynchrone Ereignisverarbeitung zeigen.



Was ist das Observer-Muster?



Das Observer-Muster (Beobachter) ist ein Verhaltensmuster der Softwareentwicklung, das einen Abonnementmechanismus schafft, der es Objekten ermöglicht, Ereignisse in anderen Objekten zu verfolgen und darauf zu reagieren.



Hauptelemente:

  • Subject (Subjekt) – das Objekt, das Ereignisse erzeugt.
  • Observer (Beobachter) – das Objekt, das Ereignisse abonniert.
  • Event (Ereignis) – die Daten, die vom Subjekt an die Beobachter übermittelt werden.


Was ist ein Event Bus?



Ein Event Bus ist ein zentralisierter Bus, der die Übertragung von Ereignissen zwischen Herausgebern (publishers) und Abonnenten (subscribers) verwaltet. Im Gegensatz zum klassischen Observer, bei dem das Subjekt direkt eine Liste der Beobachter speichert, fungiert der Event Bus als Vermittler. Dies macht das System noch flexibler und skalierbarer.



Implementierung eines Event Bus in Go



Go hat keine eingebaute Implementierung eines Event Bus, aber er kann leicht mit Goroutinen, Kanälen und Interfaces geschrieben werden. Betrachten wir eine einfache, aber vollständige Implementierung.



1. Grundlegende Typen definieren



// Event repräsentiert eine Ereignisstrukturtype Event struct {    Name string    Data interface{}}

// EventHandler – eine Ereignisbehandlungsfunktiontype EventHandler func(Event)


2. Event Bus erstellen



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

// NewEventBus erstellt einen neuen Ereignisbusfunc NewEventBus() *EventBus { return &EventBus{ handlers: make(map[string][]EventHandler), }}

// Subscribe abonniert einen Handler für ein Ereignisfunc (eb *EventBus) Subscribe(name string, handler EventHandler) { eb.mu.Lock() defer eb.mu.Unlock() eb.handlers[name] = append(eb.handlers[name], handler)}

// Publish veröffentlicht ein Ereignis synchronfunc (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. Asynchrone Veröffentlichung



Für die asynchrone Verarbeitung kann jeder Handler in einer separaten Goroutine gestartet werden:



// PublishAsync veröffentlicht ein Ereignis asynchronfunc (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)        }    }}


Anwendungsbeispiel



Betrachten wir, wie wir unseren Event Bus in einer realen Anwendung verwenden. Angenommen, wir haben ein System, das Benutzeraktionen protokolliert und Benachrichtigungen sendet.



func main() {    bus := NewEventBus()

// Abonnieren des Ereignisses "user.login" bus.Subscribe("user.login", func(e Event) { userData := e.Data.(map[string]string) fmt.Printf("Log: Benutzer %s hat sich angemeldet", userData["username"]) })

// Abonnieren desselben Ereignisses für Be

Empfehlungen