forked from steger/pr3-sose2026
added comments
parent
54886195c6
commit
fdacec5fe6
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue