1
0
Fork 0

added comments

main
Sebastian Steger 2026-04-14 14:33:22 +00:00
parent 54886195c6
commit fdacec5fe6
3 changed files with 33 additions and 3 deletions

View File

@ -6,25 +6,30 @@ import (
"gitty.informatik.hs-mannheim.de/steger/pr3-code/go/04-design-pattern/patterns" "gitty.informatik.hs-mannheim.de/steger/pr3-code/go/04-design-pattern/patterns"
) )
// Counter is a concrete implementation of the Subject interface, which maintains a count and notifies observers whenever the count changes
type Counter struct { type Counter struct {
patterns.Subject patterns.Subject // Embedding the Subject interface allows Counter to inherit its methods and be treated as a Subject, enabling it to register observers and notify them of changes
Count int Count int
} }
// NewCounter creates and returns a new instance of the Counter struct, initializing the embedded Subject using the NewSubject function from the patterns package
func NewCounter() Counter { func NewCounter() Counter {
return Counter{patterns.NewSubject(), 0} return Counter{patterns.NewSubject(), 0}
} }
// Inc increments the counter's count and notifies all registered observers of the change
func (c *Counter) Inc() { func (c *Counter) Inc() {
c.Count++ c.Count++
c.Notify() c.Notify()
} }
// Dec decrements the counter's count and notifies all registered observers of the change
func (c *Counter) Dec() { func (c *Counter) Dec() {
c.Count-- c.Count--
c.Notify() c.Notify()
} }
// CountPrinter is a concrete implementation of the Observer interface, which prints the current count whenever it receives an update notification from the Counter
type CountPrinter struct { type CountPrinter struct {
counter *Counter counter *Counter
} }
@ -33,21 +38,32 @@ func (cp *CountPrinter) Update() {
fmt.Println("count updated to ", cp.counter.Count) fmt.Println("count updated to ", cp.counter.Count)
} }
var _ patterns.Observer = (*CountPrinter)(nil) // Compile-time assertion to ensure CountPrinter implements the Observer interface
// CounterHistory is a concrete implementation of the Observer interface, which maintains a history of the counter's count values whenever it receives an update notification from the Counter
type CounterHistory struct { type CounterHistory struct {
counter *Counter counter *Counter
history []int history []int
} }
// Update appends the current count value to the history slice whenever it receives an update notification from the Counter
func (ch *CounterHistory) Update() { func (ch *CounterHistory) Update() {
ch.history = append(ch.history, ch.counter.Count) ch.history = append(ch.history, ch.counter.Count)
} }
var _ patterns.Observer = (*CounterHistory)(nil) // Compile-time assertion to ensure CounterHistory implements the Observer interface
// The main function demonstrates the usage of the Counter, CountPrinter, and CounterHistory in an interactive command-line application.
// It allows the user to increment or decrement the counter and see the updates printed, while also maintaining a history of count values.
func main() { func main() {
// Create a new Counter instance, which will serve as the Subject in the Observer pattern
counter := NewCounter() counter := NewCounter()
// Create a new CounterHistory instance and register it as an observer of the counter to track the history of count values
history := CounterHistory{&counter, []int{}} history := CounterHistory{&counter, []int{}}
counter.Register(&history) counter.Register(&history)
// Create a new CountPrinter instance and register it as an observer of the counter to print the current count whenever it changes
printer := CountPrinter{&counter} printer := CountPrinter{&counter}
counter.Register(&printer) counter.Register(&printer)
printerRegistered := true printerRegistered := true
@ -68,6 +84,7 @@ func main() {
case '-': case '-':
counter.Dec() counter.Dec()
case 'p': case 'p':
// Toggle the registration of the CountPrinter observer. If it's currently registered, unregister it; if it's currently unregistered, register it.
if printerRegistered { if printerRegistered {
counter.Unregister(&printer) counter.Unregister(&printer)
} else { } else {

View File

@ -1,33 +1,43 @@
package patterns package patterns
// Observer pattern implementation in Go
type Observer interface { type Observer interface {
Update() Update()
} }
// Subject interface defines methods for registering, unregistering, and notifying observers
type Subject interface { type Subject interface {
Register(o Observer) Register(o Observer)
Unregister(o Observer) Unregister(o Observer)
Notify() Notify()
} }
// Concrete implementation of the Subject interface. Lowercase 'subject' to make it unexported, as it will be created through the NewSubject function.
type subject struct { type subject struct {
observers map[Observer]bool observers map[Observer]bool // Using a map to store observers for efficient add/remove operations
} }
// NewSubject creates and returns a new instance of the subject
func NewSubject() Subject { func NewSubject() Subject {
// Needs to return a pointer to the subject struct to ensure that the same instance is modified when registering/unregistering observers
return &subject{ return &subject{
observers: make(map[Observer]bool), observers: make(map[Observer]bool),
} }
} }
// Register adds an observer to the subject's set of observers
// Pointer receiver is used to modify the subject's state (the observers map) when registering an observer
func (s *subject) Register(o Observer) { func (s *subject) Register(o Observer) {
s.observers[o] = true s.observers[o] = true
} }
// Unregister removes an observer from the subject's set of observers
// Pointer receiver is used to modify the subject's state (the observers map) when unregistering an observer
func (s *subject) Unregister(o Observer) { func (s *subject) Unregister(o Observer) {
delete(s.observers, o) delete(s.observers, o)
} }
// Notify calls the Update method on all registered observers to notify them of a change
func (s *subject) Notify() { func (s *subject) Notify() {
for o := range s.observers { for o := range s.observers {
o.Update() o.Update()

View File

@ -6,14 +6,17 @@ import (
"gitty.informatik.hs-mannheim.de/steger/pr3-code/go/04-design-pattern/patterns" "gitty.informatik.hs-mannheim.de/steger/pr3-code/go/04-design-pattern/patterns"
) )
// MockObserver is a test implementation of the Observer interface, used to verify that the Notify method correctly calls the Update method on registered observers
type MockObserver struct { type MockObserver struct {
callCount int callCount int
} }
// Update increments the callCount to track how many times the Update method has been called on this observer
func (mo *MockObserver) Update() { func (mo *MockObserver) Update() {
mo.callCount++ mo.callCount++
} }
// Table driven tests for the Subject's Notify method, covering various scenarios of registered and unregistered observers
func TestSubject_Notify(t *testing.T) { func TestSubject_Notify(t *testing.T) {
type observer struct { type observer struct {
MockObserver MockObserver