Back to: Design Patterns in C# With Real-Time Examples
Observer Design Pattern in C# with Examples
In this article, I will discuss the Observer Design Pattern in C# with Examples. Please read our previous article discussing the Iterator Design Pattern in C#. The Observer Design Pattern falls under the category of Behavioral Design Pattern. As part of this article, we will discuss the following pointers.
- What is the Observer Design Pattern?
- Example to understand the Observer Design Pattern in C#.
- When to use the Observer Design Pattern in C#?
What is the Observer Design Pattern?
According to GoF, the Observer Design Pattern Defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
This Design Pattern is widely used for implementing distributed event-handling systems where an object needs to notify other objects about its state changes without knowing who these objects are. In the Observer Design Pattern, an object (called a Subject) maintains a list of its dependents (called Observers). It notifies them automatically whenever any state changes by calling one of their methods. The Other names of this pattern are Producer/Consumer and Publish/Subscribe.
How Does the Observer Design Pattern Work?
The observer design pattern has two main components. They are as follows
- Subject: They are also called Publishers. When a change occurs to a subject, it should notify all its Subscribers/Observers.
- Observers: They are also called subscribers. They listen to the changes in the subjects.
Another name of the Observer is the Listener. Please have a look at the following diagram.
As shown in the above image, we can define the Subject as an object that maintains a list of observers. The Subject has methods to Register and Unregister the Observers. As you can see, there are three observers registered within the subject. If any new observer wants to register, he/she needs to call the Register method of the Subject. Again, if any observer wants to unregister, he/she needs to call the Unregister method of the subject.
The subject has some state. Whenever some changes occur in the state, the subject will notify all the registered observers by calling one of the observer methods. Once the observer gets the notification from the subject, the observer will call one of the methods of the subject to get the change state data.
Real-Time Example to Understand Observer Design Pattern:
Let us understand the Observer Design Pattern with one Real-Time Example. Please have a look at the following diagram. Here, we are taking the example of the Amazon ECommerce Application.
As you can see in the above image, three users come to the Amazon site to buy a Mobile Phone. Unfortunately, at that time, the Mobile phone was out of stock, i.e., the mobile is in the Out Of Stock state. But the above three users want to buy that particular mobile phone. The Amazon website has an option called Notify Me when the product is unavailable in stock. The above three users click the Notify Me button so that the Amazon site will notify them when the product is available.
After a few days, the Product is available, so the status of the Product is changed from Out Of Stock to Available. So, Amazon will notify all users registered with that particular product that the product is available. As we already discussed, the Observer Design Pattern has two main components, i.e., the Subject and the Observer. In our examples, the Mobile is the Subject, and three users (i.e., User1, User2, and User3) are the Observers. For a better understanding, please have a look at the following image.
As per the Observer Design Pattern, the Observers must be registered with the Subject. In our case, the three users are registered to the notification option of the Subject. When the state changes, i.e., Out of Stock to Available, the Subject will notify all subscribers. Let us see the step-by-step implementation of the above-discussed example using the Observer Design Pattern in C#.
Step1: Creating the Subject Interface
Create a class file named ISubject.cs and copy and paste the following code. The Subject knows its Observers and provides an interface for adding or removing any number of Observer objects. Here, we have created the following interface with three methods, i.e., RegisterObserver, RemoveObserver, and NotifyObservers.
namespace ObserverDesignPattern { // The Subject Interface public interface ISubject { // Register an observer to the subject. void RegisterObserver(IObserver observer); // Remove or unregister an observer from the subject. void RemoveObserver(IObserver observer); // Notify all registered observers when the state of the subject is changed. void NotifyObservers(); } }
Step2: Creating Concrete Subject
Create a class file named Subject.cs and copy and paste the following code. The ConcreteSubject object stores the registered Observers to get notifications. It is also responsible for sending the notification to its observers when the subject state is changed from Out of Stock to Available. The following class implements the ISubject interface and provides implementations for the RegisterObserver, RemoveObserver, and NotifyObservers methods.
using System; using System.Collections.Generic; namespace ObserverDesignPattern { // The ConcreteSubject class // The Subject have states and notifies all observers when the state changes. public class Subject : ISubject { // The List of Observer is going to store in the following collection object private List<IObserver> observers = new List<IObserver>(); //The following properties are going to store the Product Information private string ProductName { get; set; } private int ProductPrice { get; set; } private string Availability { get; set; } // Initializing the Product information using the constructor public Subject(string productName, int productPrice, string availability) { ProductName = productName; ProductPrice = productPrice; Availability = availability; } //The following Method is going to return the State of the Product public string GetAvailability() { return Availability; } //The following Method is going to set the State of the Product public void SetAvailability(string availability) { this.Availability = availability; Console.WriteLine("Availability changed from Out of Stock to Available."); NotifyObservers(); } // The observer will register with the Product using the following method public void RegisterObserver(IObserver observer) { Console.WriteLine("Observer Added : " + ((Observer)observer).UserName); observers.Add(observer); } // The observer will unregister from the Product using the following method public void RemoveObserver(IObserver observer) { Console.WriteLine("Observer Removed : " + ((Observer)observer).UserName); observers.Remove(observer); } // The following Method will be sent notifications to all observers public void NotifyObservers() { Console.WriteLine("Product Name :" + ProductName + ", product Price : " + ProductPrice + " is Now available. So, notifying all Registered users "); Console.WriteLine(); foreach (IObserver observer in observers) { //By Calling the Update method, we are sending notifications to observers observer.Update(Availability); } } } }
Step3: Creating Observer Interface:
Create a class file named IObserver.cs and copy and paste the following code. The Observer defines an updating interface for objects that should be notified of changes in a Subject. That means whenever the subject’s state changes, the subject will call this Update method of the observer.
namespace ObserverDesignPattern { // The Observer Interface public interface IObserver { // Receive Notification from Subject void Update(string availability); } }
Step4: Creating Concrete Observer
Create a class file named Observer.cs and copy and paste the following code. The following class maintains a reference to a ConcreteSubject object, implements the Observer interface, and provides implementations for the Update method.
using System; namespace ObserverDesignPattern { // The ConcreteObserver class // Concrete Observer react to the updates issued by the Subject public class Observer : IObserver { //The following Property is going to hold the observer's name public string UserName { get; set; } //Creating the Observer public Observer(string userName) { UserName = userName; } //Registering the Observer with the Subject public void AddSubscriber(ISubject subject) { subject.RegisterObserver(this); } //Removing the Observer from the Subject public void RemoveSubscriber(ISubject subject) { subject.RemoveObserver(this); } //Observer will get a notification from the Subject using the following Method public void Update(string availabiliy) { Console.WriteLine("Hello " + UserName + ", Product is now " + availabiliy + " on Amazon"); } } }
Step5: Client
The Program class is going to be the Client code in our example. To test that everything is working as expected, let’s modify the Main method of the Program class as shown below. The following client code is self-explained, so please go through the comment lines for a better understanding.
using System; namespace ObserverDesignPattern { class Program { static void Main(string[] args) { //Create a Product with Out of Stock Status Subject RedMI = new Subject("Red MI Mobile", 10000, "Out Of Stock"); //User Anurag will be created and the user1 object will be registered to the subject Observer user1 = new Observer("Anurag"); user1.AddSubscriber(RedMI); //User Pranaya will be created and the user1 object will be registered to the subject Observer user2 = new Observer("Pranaya"); user2.AddSubscriber(RedMI); //User Priyanka will be created and the user3 object will be registered to the subject Observer user3 = new Observer("Priyanka"); user3.AddSubscriber(RedMI); Console.WriteLine("Red MI Mobile current state : " + RedMI.GetAvailability()); Console.WriteLine(); user3.RemoveSubscriber(RedMI); // Now the product is available RedMI.SetAvailability("Available"); Console.Read(); } } }
Output:
Observer Design Pattern UML or Class Diagram
Let us understand the Class Diagram or UML Diagram of the Observer Design Pattern and understand the different components. Please have a look at the following image.
As you can see in the above image, the Observer Design Pattern consists of four components. They are as follows:
- Subject: This interface will declare the operations for adding and removing observers and send notifications to the registered observers when the subject state changes. We can add any number of observers. In our example, it is the ISubject interface.
- ConcreteSubject: This will be a concrete class, and this class should implement the Subject interface. This class maintains its own state, and when the state is changed, it will send notifications to all observers by calling the observer’s update method. In our example, it is the Subject class.
- Observer: This will be an interface that defines an updating interface for objects that should be notified when the subject state changes. In our example, it is the IObserver interface.
- ConcreteObserver: This will be a class that implements the Observer interface. This interface provides one method to determine what changes have occurred with the subject. The Subject will call this Observer method to send the notification. In our example, it is the Observer class.
Advantages of Observer Design Pattern:
- Loose Coupling: The subject and observers are loosely coupled. The subject knows nothing about the observers except that they implement the observer interface.
- Dynamic Relationships: You can add and remove observers dynamically at runtime.
- Broadcast Communication: The subject broadcasts notifications to all interested observers without knowing their details.
Use Cases Observer Design Pattern:
- When a change to one object requires changing others, you don’t know how many objects need to be changed.
- When an object should be able to notify other objects without making assumptions about who these objects are.
For example, a mailing list where every time an event happens (i.e., a new product, a gathering, etc.), a message needs to be sent to the users who subscribed to the list.
The Company needs to notify all its employees of any decision they make. Here, the Company is the Subject, and the Employees are the Observers. Any change in the company’s policy and the company needs to notify all its employees or, you can say, Observers.
In the next article, I will discuss Real-Time Examples of Observer Design Patterns in C# with Examples. In this article, I explain the Observer Design Pattern in C# step by step with an example. I hope you understand the need and use of the Observer Design Pattern in C#.
Thank you for this understandable explanation.
dotnettutorials.net is really helpful for me.
Greetings
Thank you so much for finding our content useful.
very good at explaining things. Thank you
Your valuable feedback is means a lot to us.
very understanding explanations, thanks
Thank you so much. Please keep reading and keep giving your valuable feedback.
Very Good Simple language Understanding real time examples rather than foo( ) class and such typical examples.
I Love the way you explain concepts in simple language 🙂
Thank you
Thank you for finding our articles useful and please keep reading, keep sharing, and keep giving valuable feedback an suggestions to us for the betterment.
Its a Doubt,
1. I think the list of observers that we cannot keep it in memory right ? because may be the product will be available after a month. So in real time implementations, is it like the registration will be saved in to DB and that will be read from DB based on the product availability ?
2.Is it similar to publish subscribe ? if yes, then publish subscribe will be working as a delegate(event) and which will be notified the event to the subscribers whoever subscribe to it .
if not, what is the difference between pub sub and observer pattern
how much more productive and memory efficient is this pattern than regular events ?