Behavioral Design Pattern - Observer
Design Pattern
10 Articles
In this article, let's learn about Observer Design Pattern
in .NET.
Table of Contents
Introduction
In this article, we'll explore the Observer
pattern, a behavioral design pattern
used to create a one-to-many dependency
between objects so that when one object changes state
,
all its dependents are notified and updated automatically. This pattern is also known as the Publish-Subscribe
or
Pub/Sub pattern
. We'll start by explaining the pattern using a practical example. We'll implement a simplified
order management system where different parts of an order need to stay in sync. Then, we'll delve into the pattern's structure, use cases,
consequences, and related patterns. Let's get started!
The Observer pattern, as described in the Gang of Four
design patterns book, aims to define a dependency between
objects such that when one object changes, all its dependents are notified and updated automatically. This pattern is commonly used in applications
where data changes need to propagate throughout the system without tightly coupling
components.
Example Scenario: Order
and OrderItem
in an Order Management System
Let's consider a scenario where we manage orders and their associated items in an order management system. When an OrderItem (like the quantity or price of an item) is updated, the Order needs to recalculate its total to reflect these changes. This setup mirrors the Observer pattern:
OrderItem:
Represents the individual items in an order, with properties such as quantity and unit price.Order:
Represents the overall order, which needs to keep track of total cost and other details based on its items.
Rather than the Order directly querying each OrderItem for changes, we can use the Observer pattern to notify the Order whenever an OrderItem is updated. This way, the system remains flexible and easy to extend.
Structure
The Observer pattern involves several key components:
Subject:
The object that holds the state and notifies observers of any state changes. In our example, the OrderItem acts as the subject.Observer:
An interface or abstract class defining the method to be called when the subject's state changes. Here, Order is our observer interface.Concrete Subject:
The specific object holding the state of interest. For this example, it's the OrderItem class.Concrete Observer:
The specific implementation of the observer interface. In our case, each Order implements an observer to track its changes.
Here's how we can implement the Observer pattern in our order management system:
Code Sample - Publisher Code Sample - Observer Pattern
In the above code we are adding Observer (Order) using AddObserver
and removing Observer (Order) using
RemoveObserver
. NotifyOrderItemProcessed
notifies all subscribed observers
(order) by calling their ReceiveOrderItemProcessedNotification
method. OrderItem implements the above
abstract class
and calls NotifyOrderItemProcessed method whenever there is a change in OrderItem.
Code Sample - Listener Code Sample - Observer Pattern
In the above code OrderViewModel
listens
for changes in
OrderItemViewModel
instances and recalculates the total amount using CalculateTotalAmount
whenever any item is updated, ensuring the total is always accurate.
Demo - Observer Pattern Demo
Let's try Observer
Demo, Click on the Add Order Item
and
Remove Order Item
and change Quantity and Price
to see the observer pattern in action.
The results will be displayed at the bottom of table.
Code Sample - Observer Pattern Demo
Quantity | Price | Line Amount | |
---|---|---|---|
Total | ¤0.00 |
Use Cases
The Observer pattern is beneficial in several scenarios:
Dynamic Relationships:
When the number of dependents (observers) that need to be updated can change at runtime, like dynamically adding or removing items from an order.Decoupling Components:
To avoid tight coupling between components, like separating order calculation logic from item management.Event Handling Systems:
In scenarios like GUI frameworks, where user interactions need to notify various components without tightly binding them together.
Advantages
Loose Coupling:
Subjects and observers remain loosely coupled, which allows for greater flexibility and easier maintenance.
Disadvantages
Potential Performance Impact:
If not managed carefully, especially with a large number of observers, the notification process might lead to performance issues.Change Cascades:
Unintended cascades of changes can occur if observers can change the state of subjects in response to notifications.
Related Patterns
The Observer pattern is closely related to several other design patterns:
Mediator:
Centralizes complex communication and control logic between objects, effectively reducing dependencies.Command:
Encapsulates a request as an object, thereby allowing for parameterization and queuing of requests.Chain of Responsibility:
Allows a request to pass along a chain of potential handlers until it is processed.
Summary
In this module, we explored the Observer
pattern through the lens of an order management system. We saw how
this pattern allows for automatic updates
and notifications
across related
components, promoting loose coupling
and flexibility
. We also covered use
cases, consequences, and related patterns to provide a comprehensive understanding of its applications.