Created
March 2, 2022 03:42
-
-
Save thalesfsp/50c026de9c576980bb3c38f79d09a66a to your computer and use it in GitHub Desktop.
Subject <-> Observer behavioural design pattern
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// It is mainly used for implementing distributed event handling systems, in "event driven" software. | |
// Channels could have been used. | |
package main | |
////// | |
// Starts here. | |
////// | |
func main() { | |
// Create a new subject. | |
readinessSubject := NewSubject(false) | |
// Create observers. | |
apiObserver := NewObserver("API") | |
observerB := NewObserver("Status") | |
// Attach our Observers to readinessSubject. | |
readinessSubject.Attach(apiObserver) | |
readinessSubject.Attach(observerB) | |
// Start notification. | |
readinessSubject.Notify() | |
// Change readiness. | |
readinessSubject.SetReadiness(true) | |
// Change readiness again. | |
readinessSubject.SetReadiness(false) | |
// Change readiness again. | |
readinessSubject.SetReadiness(true) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
) | |
////// | |
// Interfaces. | |
////// | |
// Observer actions definition. | |
type IObserver interface { | |
// Do something because the subject ready changed. | |
Do(string) | |
} | |
////// | |
// Object definition. | |
////// | |
type Observer struct { | |
// Name of the observer. | |
name string | |
} | |
////// | |
// IObserver implementation. | |
////// | |
// Do defines how to react when a subject changed. | |
func (s *Observer) Do(t bool) { | |
fmt.Printf(`%s observer has been notified. New readiness value "%v"`+"\n", s.name, t) | |
} | |
////// | |
// Factory. | |
////// | |
// NewObserver creates a new observer. | |
func NewObserver(name string) Observer { | |
return Observer{ | |
name: name, | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"errors" | |
) | |
////// | |
// Interfaces. | |
////// | |
// Subject actions definition. | |
type ISubject interface { | |
// Attach an Observer to observe the subject. | |
Attach(o Observer) (bool, error) | |
// Detach an Observer which is observing the subject. | |
Detach(o Observer) (bool, error) | |
// Notify observers of a change. | |
// | |
// NOTE: This is why it's pattern from the behavioral category. | |
Notify() (bool, error) | |
} | |
////// | |
// Object definition. | |
////// | |
type Subject struct { | |
// Could be anything. For flexibility, could be an `interface{}`. | |
// It would require type casting. | |
ready bool | |
// List of observers. | |
observers []Observer | |
} | |
////// | |
// ISubject implementation. | |
////// | |
// Attach an observer to observe the subject. | |
func (s *Subject) 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 | |
} | |
// Detach an observer which is observing the subject. | |
func (s *Subject) 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") | |
} | |
// Notify observers of a change. | |
func (s *Subject) Notify() (bool, error) { | |
for _, observer := range s.observers { | |
observer.Do(s.ready) | |
} | |
return true, nil | |
} | |
////// | |
// Accessors. | |
////// | |
// SetReadiness update readiness. | |
func (s *Subject) SetReadiness(ready bool) { | |
s.ready = ready | |
// Notifies all observers of the change. | |
s.Notify() | |
} | |
////// | |
// Factory. | |
////// | |
// NewSubject creates a new subject. | |
func NewSubject(ready bool) Subject { | |
return Subject{ | |
ready: ready, | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment