How to Implement the Observer Pattern in Go

Implement the Observer pattern in Go by defining Subject and Observer interfaces with Attach, Detach, Notify, and Update methods to manage state changes.

Implement the Observer pattern in Go by defining a Subject interface with Attach, Detach, and Notify methods, and a Observer interface with an Update method.

package main

import "fmt"

type Observer interface {
	Update(subject Subject)
}

type Subject interface {
	Attach(o Observer)
	Detach(o Observer)
	Notify()
}

type ConcreteSubject struct {
	observers []Observer
	state     int
}

func (s *ConcreteSubject) Attach(o Observer) {
	s.observers = append(s.observers, o)
}

func (s *ConcreteSubject) Detach(o Observer) {
	for i, obs := range s.observers {
		if obs == o {
			s.observers = append(s.observers[:i], s.observers[i+1:]...)
			break
		}
	}
}

func (s *ConcreteSubject) Notify() {
	for _, obs := range s.observers {
		obs.Update(s)
	}
}

func (s *ConcreteSubject) SetState(state int) {
	s.state = state
	s.Notify()
}

func (s *ConcreteSubject) GetState() int {
	return s.state
}

type ConcreteObserver struct {
	name  string
	state int
}

func (o *ConcreteObserver) Update(subject Subject) {
	if s, ok := subject.(*ConcreteSubject); ok {
		o.state = s.GetState()
		fmt.Printf("Observer %s updated: state is now %d\n", o.name, o.state)
	}
}

func main() {
	subject := &ConcreteSubject{}
	o1 := &ConcreteObserver{name: "O1"}
	o2 := &ConcreteObserver{name: "O2"}

	subject.Attach(o1)
	subject.Attach(o2)

	subject.SetState(10)
	subject.Detach(o1)
	subject.SetState(20)
}