1
\$\begingroup\$

I am trying to practice the Observer design pattern in Golang, here is my code. I would be pleased to receive your comments, improvements, etc.

package observer

import (
    "container/list"
    "fmt"
    "math/rand"
)

//interface that receive updates
type Observer interface{
    Update(s *Subject)
}

// interface that manage notifying
type Subject struct{
    observers *list.List
    status int
}

func NewSubject() *Subject {
    //this can be categorized from database etc
    return &Subject{observers:new(list.List)}
}

func (s *Subject) Attach(o Observer){
    s.observers.PushBack(o)
}

func (s *Subject) DeAttach(o Observer){
    for obs := s.observers.Front(); obs != nil; obs = obs.Next() {
        if obs.Value.(Observer) == o {
            s.observers.Remove(obs)
        }
    }
}

func (s *Subject) notify(){
    for obs := s.observers.Front(); obs != nil; obs = obs.Next() {
        observer := obs.Value.(Observer)
        observer.Update(s)
    }
}

// some business logic function to notify
func (s *Subject) ScanData() {

    // just generate random number for status
    // this can be a business logic in real world to calculate or fetch status for a specific source or logic
    s.status = rand.Intn(1000)
    s.notify()
}

//Concrete class A for Observer
type ConcreteNotifierA struct{
}

func NewConcreteNotifierA() *ConcreteNotifierA {
    return &ConcreteNotifierA{
    }
}

func (a *ConcreteNotifierA) Update(s *Subject) {
    if s.status > 500 {
        fmt.Printf("Status is bigger than 500: %v \n", s.status)
    }
}


//Concrete class B for Observer
type ConcreteNotifierB struct{
}

func NewConcreteNotifierB() *ConcreteNotifierB {
    return &ConcreteNotifierB{
    }
}

func (b *ConcreteNotifierB) Update(s *Subject) {
    if s.status < 501 {
        fmt.Printf("Status is less than 500: %v \n", s.status)
    }
}

And here is testing:

subject := observer.NewSubject()
concreteObserverA := observer.NewConcreteNotifierA()
concreteObserverA1 := observer.NewConcreteNotifierA()
concreteObserverB := observer.NewConcreteNotifierB()
concreteObserverB1 := observer.NewConcreteNotifierB()

subject.Attach(concreteObserverA)
subject.Attach(concreteObserverA1)
subject.Attach(concreteObserverB)
subject.Attach(concreteObserverB1)

fmt.Printf("First Scan\n")
subject.ScanData()

subject.DeAttach(concreteObserverB)
subject.DeAttach(concreteObserverA)

fmt.Printf("Second Scan\n")
subject.ScanData()

EDIT: Let's say the goal is on different type of "Status", different type of subscribers will be notified.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ What's that code supposed to do in practice? Elaborate please. \$\endgroup\$ Oct 27, 2019 at 17:18
  • \$\begingroup\$ Let's say the goal is on different type of "Status", different type of subscribers will be notified. \$\endgroup\$
    – Mazdak
    Oct 27, 2019 at 17:42
  • 1
    \$\begingroup\$ Your code looks quite hypothetical. Please post real code here for review. \$\endgroup\$ Oct 27, 2019 at 17:45
  • \$\begingroup\$ Typo: Detach, not DeAttach. \$\endgroup\$
    – Eyal
    Dec 10, 2019 at 14:58

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Browse other questions tagged or ask your own question.