This problem is pretty common: an object should notify all its subscribers when some event occurs. In C++ we may use boost::signals
or something else. But how to do this in Go language? It would be nice to see some working code example where a couple of objects are subscribed to a publisher and process notifications.
Thanks
Observer is a behavioral design pattern. It specifies communication between objects: observable and observers. An observable is an object which notifies observers about the changes in its state. For example, a news agency can notify channels when it receives news.
The observer pattern is a software design pattern in which an object, named the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.
Yes, it is. The observer pattern is also called the publish/subscribe pattern, which is exactly what events allow you to do.
In Listener Design Pattern, when a event happens, the event raiser notifies a global mediator (the singleton Events. instance ), because it has no information about the event handlers. While in Observer Pattern, when any change happens, the observed subject directly notifies all the observers.
This is actually pretty simple in Go. Use channels. This is the kind of thing they're made for.
type Publish struct {
listeners []chan *Msg
}
type Subscriber struct {
Channel chan *Msg
}
func (p *Publisher) Sub(c chan *Msg) {
p.appendListener(c)
}
func (p *Publisher) Pub(m *Msg) {
for _, c := range p.listeners {
c <- Msg
}
}
func (s *Subscriber) ListenOnChannel() {
for {
data := <-s.Channel
//Process data
}
}
func main() {
for _, v := range subscribers {
p.Sub(v.Channel)
go v.ListenOnChannel()
}
//Some kind of wait here
}
Obviously this isn't exactly a working code sample. But it's close.
Here I give a classific implementation without channels, be free to refer this post
Assumed Example: Suppose you are interested in the stock market. You have the following needs: You want to keep track of the stock prices of a particular company (e.g. Apple Inc). You would not like to miss any stock price update especially if the price is dropping to a certain point. You would like to be notified of all the stock price updates.
interfaces:
// Subject interface
type Subject interface {
Attach(o Observer) (bool, error)
Detach(o Observer) (bool, error)
Notify() (bool, error)
}
// Observer Interface
type Observer interface {
Update(string)
}
Concrete Observer object
// Concrete Observer: StockObserver
type StockObserver struct {
name string
}
func (s *StockObserver) Update(t string) {
// do something
println("StockObserver:", s.name, "has been updated,", "received subject string:", t)
}
Concrete Subject object
// Concrete Subject: stockMonitor
type StockMonitor struct {
// internal state
ticker string
price float64
observers []Observer
}
func (s *StockMonitor) Attach(o Observer) (bool, error) {
for _, observer := range s.observers {
if observer == o {
return false, errors.New("Observer already exists")
}
}
s.observers = append(s.observers, o)
return true, nil
}
func (s *StockMonitor) Detach(o Observer) (bool, error) {
for i, observer := range s.observers {
if observer == o {
s.observers = append(s.observers[:i], s.observers[i+1:]...)
return true, nil
}
}
return false, errors.New("Observer not found")
}
func (s *StockMonitor) Notify() (bool, error) {
for _, observer := range s.observers {
observer.Update(s.String())
}
return true, nil
}
func (s *StockMonitor) SetPrice(price float64) {
s.price = price
s.Notify()
}
func (s *StockMonitor) String() string {
convertFloatToString := strconv.FormatFloat(s.price, 'f', 2, 64)
return "StockMonitor: " + s.ticker + " $" + convertFloatToString
}
main.go
func main() {
// Create a new stockMonitor object
stockMonitor := &StockMonitor{
ticker: "AAPL",
price: 0.0,
}
observerA := &StockObserver{
name: "Observer A",
}
observerB := &StockObserver{
name: "Observer B",
}
// Attach our Observers to the stockMonitor
stockMonitor.Attach(observerA)
stockMonitor.Attach(observerB)
// Start the stockMonitor
stockMonitor.Notify()
// Change the price of the stockMonitor
stockMonitor.SetPrice(500)
// Detach an Observer from the stockMonitor
stockMonitor.Detach(observerA)
// Change the price of the stockMonitor
stockMonitor.SetPrice(528)
}
In this part
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With