1. What is the Observer Pattern
The Observer Pattern is a behavioral design pattern used to establish a one-to-many dependency between objects. Specifically, when an object (referred to as the subject or observable) changes, all its dependencies (referred to as observers) are notified and updated automatically. This pattern allows for loose coupling between subjects and observers, thereby achieving decoupling and flexibility between objects.
2. Characteristics and Advantages of the Observer Pattern
The Observer Pattern has the following characteristics and advantages:
- Loose coupling between subjects and observers, where the subject does not need to know the specific implementation details of the observers.
- Dynamic addition and removal of observers, making the system more flexible.
- Follows the open-closed principle between subjects and observers, enabling independent extension and reusability.
- Can establish a one-to-many dependency relationship, where a subject can have multiple observers.
3. Examples of Practical Applications of the Observer Pattern
The Observer Pattern has many practical applications in real life, such as:
- Event handling mechanism in GUI interfaces, like handling actions when a button is clicked.
- Real-time stock market quotes push.
- Notification of promotional activities on e-commerce platforms.
4. Implementation of the Observer Pattern in Golang
4.1 UML Class Diagram
4.2 Example Introduction
In this example, we have a subject (Subject) and two observers (ObserverA and ObserverB). The subject can register, unregister, and notify observers.
4.3 Implementation Steps
4.3.1 Create Subject Interface and Concrete Subject Class
type Subject interface {
RegisterObserver(observer Observer)
RemoveObserver(observer Observer)
NotifyObservers()
}
type ConcreteSubject struct {
observers []Observer
}
// Register listener object
func (subject *ConcreteSubject) RegisterObserver(observer Observer) {
subject.observers = append(subject.observers, observer)
}
// Remove listener object
func (subject *ConcreteSubject) RemoveObserver(observer Observer) {
for i, obs := range subject.observers {
if obs == observer {
subject.observers = append(subject.observers[:i], subject.observers[i+1:]...)
break
}
}
}
// Trigger event notification
func (subject *ConcreteSubject) NotifyObservers() {
for _, observer := range subject.observers {
observer.Update()
}
}
4.3.2 Create Observer Interface and Concrete Observer Classes
type Observer interface {
Update()
}
type ConcreteObserverA struct {}
func (observer *ConcreteObserverA) Update() {
fmt.Println("Observer A is notified.")
}
type ConcreteObserverB struct {}
func (observer *ConcreteObserverB) Update() {
fmt.Println("Observer B is notified.")
}
4.4 Example Code Demo
func main() {
subject := &ConcreteSubject{}
observerA := &ConcreteObserverA{}
observerB := &ConcreteObserverB{}
subject.RegisterObserver(observerA)
subject.RegisterObserver(observerB)
subject.NotifyObservers()
subject.RemoveObserver(observerA)
subject.NotifyObservers()
}
Output:
Observer A is notified.
Observer B is notified.
Observer B is notified.
The above example code demonstrates the specific implementation of the observer pattern. The subject (ConcreteSubject) registered two observers (ObserverA and ObserverB), and then notified these two observers. After that, observer A was unregistered from the subject and the remaining observer B was notified again.