Go Patterns
How to Implement Observer Pattern in Go
Behavioral Go Design Pattern
Observer Pattern
The Observer Pattern defines a one-to-many dependency between Notifier and Observers. When Notifier changes its state all Observers are notified with Events.
This pattern can be used in the event-driven code. When one parts of the code have to react on changes in another part.
Basic Types and Interfaces
We will start with defining type for Event
.
// Event defines an indication of a some occurence
type Event struct {
// Data in this case is a simple int.
Data int
}
Next step will be to write an interface for Observer
.
// Observer defines a standard interface
// to listen for a specific event.
type Observer interface {
// OnNotify allows to publsh an event
OnNotify(Event)
}
Third step is to implement interface for the Notifier
.
This interface has 3 methods:
Register(Observer)
Unregister(Observer)
Notify(Event)
// Notifier is the instance being observed.
type Notifier interface {
// Register itself to listen/observe events.
Register(Observer)
// Remove itself from the collection of observers/listeners.
Unregister(Observer)
// Notify publishes new events to listeners.
Notify(Event)
}
Implement Concrete Types
Now let’s implement concrete Observer
using our Observer
interface.
type observer struct {
id int
}
func (o *observer) OnNotify(e Event) {
fmt.Printf(
"observer %d recieved event %d\n",
o.id, e.Data,
)
}
Next step is to define Notifier
for our Notifier
interface.
type notifier struct {
observers map[Observer]struct{}
}
func (n *notifier) Register(o Observer) {
n.observers[o] = struct{}{}
}
func (n *notifier) Unregister(o Observer) {
delete(n.observers, o)
}
func (n *notifier) Notify(e Event) {
for o := range n.observers {
o.OnNotify(e)
}
}
Usage Example
Get all things together and write the main
function.
package main
func main() {
n := notifier{
observers: map[Observer]struct{}{},
}
n.Register(&observer{1})
n.Register(&observer{2})
n.Notify(Event{1})
n.Notify(Event{101})
n.Notify(Event{9999})
}
And output will be
# Output
➜ go-patterns go run ./behavioral/observer
observer 1 recieved event 1
observer 2 recieved event 1
observer 1 recieved event 101
observer 2 recieved event 101
observer 1 recieved event 9999
observer 2 recieved event 9999
Conclusion
Implementing a basic Observer Pattern
is not a hard task, and it is often implemented in the event-driven
code. In those systems, the Notifier
is usually named a “stream of events”.
Happy coding!
Code examples can be found in my GitHub repo pavel-fokin/go-patterns.