What is the Observer Design Pattern?
The observer design pattern is a behavioral design pattern that allows loosely coupled communication between objects. In this pattern, an object (called the Subject) maintains a list of objects that depend on it (called the Observer Observer) and automatically notifies them when the state changes. The observer pattern can be used to implement an event-driven system where interactions between objects are accomplished through publishing and subscribing to events.
Application scenario: Order processing system
In an order processing system, the status of the order may change, such as creation, payment, shipment, cancellation, etc. When the order status changes, we hope to notify relevant observers to perform corresponding processing, such as updating inventory, sending notifications, etc.
Implement the observer design model
In Golang, channels and goroutines can be used to implement observer design patterns.
First, we define an order structure that contains the basic information and status of the order:
type Order struct { ID string Status string }
Then, we define an observer interface, including aUpdate
Method, used to handle notification of order status changes:
type Observer interface { Update(order *Order, wg *) }
Next, we define a theme structure, using channel and goroutine to notify observers:
type Subject struct { observers []Observer } func (s *Subject) Register(observer Observer) { = append(, observer) } func (s *Subject) Notify(order *Order) { wg := {} (len()) errCh := make(chan error, len()) for _, observer := range { go func(obs Observer) { defer () err := (order, &wg) if err != nil { errCh <- err } }(observer) } () close(errCh) // Handle exceptions for err := range errCh { ("Error occurred:", err) } }
We first created aerrCh
(Typechan error
) to receive exceptions that may occur during the observer's processing. Then, in each observer's goroutine we pass it through closureobserver
And check whether any exceptions have occurred after the processing is completed. If there is an exception, we send it toerrCh
middle.
existNotify
At the end of the method, we closed iterrCh
channel and passrange
Loop to handle all exceptions.
Next, we achieve two observers: inventory observer and notification observer.
Inventory Observer is used to update inventory status:
type InventoryObserver struct{} func (io *InventoryObserver) Update(order *Order, wg *) { defer () // Update inventory status ("Inventory Observer: Order %s status changed to %s\n", , ) }
Notification observers are used to send notifications:
type NotificationObserver struct{} func (no *NotificationObserver) Update(order *Order, wg *) { defer () // Send notification ("Notification Observer: Order %s status changed to %s\n", , ) }
Finally, we use observer pattern in the main function to handle notifications of order state changes:
func main() { order := &Order{ ID: "123", Status: "Created", } subject := &Subject{} (&InventoryObserver{}) (&NotificationObserver{}) // Simulate order status changes = "Paid" (order) = "Shipped" (order) }
We created an order object and a topic object and registered the inventory observer. Then, we simulate the change in the order status, by callingNotify
The method concurrently notifies the observer for processing.
By using channel and goroutine, we can implement concurrent processing of observer mode to improve the performance and responsiveness of the system.
Some advantages of using observer design patterns
- 1. Loose coupling: Observer mode can decouple observer and subject (or by observer) objects. The observer only needs to pay attention to the state changes of the subject, not to understand the specific implementation details. This can make the system more flexible and scalable.
- 2. Reusability: By separating observers and subject objects, they can be reused in different contexts. For example, the same observer can be used in different business scenarios to handle different topic objects.
- 3. Easy to expand: Observer mode can be easily expanded when new observers or topics are needed. Just implement a new observer or topic object and register it in the topic object.
- 4. Event-driven: Observer mode is suitable for event-driven systems. When the state of the subject object changes, all observers can be notified to perform corresponding processing by triggering events.
If you do not use the Observer Design Pattern
The order business may be implemented in a tighter coupling way. Here is a sample code showing how to deal with order status changes without using observer mode:
type Order struct { ID string Status string } type OrderProcessor struct { inventoryObserver *InventoryObserver notificationObserver *NotificationObserver } func NewOrderProcessor() *OrderProcessor { return &OrderProcessor{ inventoryObserver: &InventoryObserver{}, notificationObserver: &NotificationObserver{}, } } func (op *OrderProcessor) Process(order *Order) { // Update inventory (order) // Send notification (order) } func main() { order := &Order{ ID: "123", Status: "Created", } op := NewOrderProcessor() // Simulate order status changes = "Paid" (order) = "Shipped" (order) }
In this example,OrderProcessor
The object is responsible for handling order status changes. It containsInventoryObserver
andNotificationObserver
object, and inProcess
The method calls them in sequenceUpdate
Method to handle order status changes.
There are some problems with this implementation:
1. Tight coupling:OrderProcessor
The object depends directly onInventoryObserver
andNotificationObserver
Object. If you need to add or delete other observers, you need to modify themOrderProcessor
code, resulting in reduced maintainability and scalability of the code.
2. Code duplication: Whenever there is a new observer that needs to handle the order status changes, it is necessary toOrderProcessor
Add the corresponding code to it. This will lead to duplication and redundancy of the code.
3. Poor scalability: It is difficult to add new observers to the system without using observer mode, because it needs to be modified every timeOrderProcessor
code.
The above is the detailed content of the example exploration of the Golang Observer Mode optimization order processing system. For more information about the Golang Observer Mode, please pay attention to my other related articles!