How to Implement the Publish-Subscribe Pattern in Go

Implement the Publish-Subscribe pattern in Go using channels and a Topic struct to decouple message producers from multiple consumers.

Use Go channels to decouple producers and consumers, allowing multiple subscribers to receive messages from a single publisher without direct references. Create a Subscriber interface, a Topic struct holding a slice of channels, and a Publish method that iterates over subscribers to send data concurrently.

package main

import (
	"fmt"
	"sync"
)

type Subscriber interface {
	Receive(msg string)
}

type Topic struct {
	name       string
	subscribers []Subscriber
	mu         sync.RWMutex
}

func (t *Topic) Subscribe(s Subscriber) {
	t.mu.Lock()
	defer t.mu.Unlock()
	t.subscribers = append(t.subscribers, s)
}

func (t *Topic) Publish(msg string) {
	t.mu.RLock()
	defer t.mu.RUnlock()
	for _, s := range t.subscribers {
		go s.Receive(msg)
	}
}

type Logger struct {
	id string
}

func (l *Logger) Receive(msg string) {
	fmt.Printf("Logger %s received: %s\n", l.id, msg)
}

func main() {
	topic := &Topic{name: "news"}
	topic.Subscribe(&Logger{id: "A"})
	topic.Subscribe(&Logger{id: "B"})
	topic.Publish("Breaking News")
}