package main import ( "fmt" "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 { 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 } // 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 { return Counter{patterns.NewSubject(), 0} } // Inc increments the counter's count and notifies all registered observers of the change func (c *Counter) Inc() { c.Count++ c.Notify() } // Dec decrements the counter's count and notifies all registered observers of the change func (c *Counter) Dec() { c.Count-- 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 { counter *Counter } func (cp *CountPrinter) Update() { 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 { counter *Counter 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() { 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() { // Create a new Counter instance, which will serve as the Subject in the Observer pattern 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{}} 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} counter.Register(&printer) printerRegistered := true var input string for { fmt.Print("Enter a command (+: increment, -: decrement, q: quit): ") fmt.Scanln(&input) if len(input) != 1 { fmt.Println("Please enter a single character.") continue } switch input[0] { case '+': counter.Inc() case '-': counter.Dec() 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 { counter.Unregister(&printer) } else { counter.Register(&printer) } printerRegistered = !printerRegistered case 'q': fmt.Println("Exiting...") fmt.Println(history.history) return default: fmt.Println("Unknown command. Use '+', '-', or 'q'.") } } }