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.
The Observer Design Pattern is a Software Design Pattern in which an object (called a Subject) maintains a list of its dependents (called Observers) and notifies them automatically whenever any state changes by calling one of their methods.
The Observer Design Pattern defines a one-to-many dependency between objects so that when one object’s state changes, all its dependents are notified and updated automatically. 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 observers who are registered in the subject 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 with the name ISubject.cs and copy and paste the following code into it. 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 with the name Subject.cs and copy and paste the following code into it. 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. The following class code is self-explained, so please go through the comment lines for a better understanding.
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 with the name IObserver.cs and then copy and paste the following code into it. 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 with the name Observer.cs and copy and paste the following code into it. The following class maintains a reference to a ConcreteSubject object, implements the Observer interface, and provides implementations for the Update method. The following class code is self-explained, so please go through the comment lines for a better understanding.
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 Main method of 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 will be an interface that declares the operations for adding and removing observers and sends 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.
Typical Use Cases:
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. This is a simple real-world example of the Observer Design Pattern.
When to use the Observer Design Pattern in C#?
The Observer design pattern is particularly valuable when a change in one object (the subject) needs to be communicated to one or more other objects (the observers) without the subject needing to know about these observers explicitly. Here are scenarios in which the Observer pattern is a good fit:
- Event Handling: This pattern is a core concept behind event handling in many frameworks, including .NET. When you have a button and want to execute certain code upon clicking it, you use a variant of the Observer pattern.
- Broadcast Communication: When an object needs to broadcast data to multiple entities but shouldn’t be concerned with who those entities are or what they do. An example might be a logging system that broadcasts log entries to various targets (console, file, remote server).
- Monitoring Systems: Systems that monitor for specific conditions and then trigger alerts. The observers, in this case, are the alerting mechanisms.
- Chat Rooms: Where each user (observer) gets notified when someone posts a message.
- Stock Market Applications: All registered investors (observers) can get notifications when the stock value changes.
- Push Model in Web: Technologies like WebSockets or SignalR where the server pushes updates to client browsers whenever there’s new data.
- Game Programming: Games often involve objects that need to be notified of events, like an achievement system getting notified of game events.
- News Services: A news publisher can notify all subscribers whenever there’s breaking news.
- Middleware Products: Message Queues, Publishers/Subscriber systems, etc., that need to notify consumers of new messages or events.
However, be cautious about:
- Performance Concerns: With many observers or frequent updates, the pattern can introduce performance issues since every change to the subject could lead to a cascade of updates.
- Unexpected Side Effects: If observers have side effects when being updated, these side effects can compound and lead to unexpected behavior.
- Memory Leaks: In languages and environments where memory management is a concern (like in older versions of .NET before garbage collection was improved), care must be taken to deregister observers when they are no longer needed, or they could lead to memory leaks.
So, while the Observer pattern is a powerful tool, it’s crucial to use it judiciously and understand its implications in the context of the broader system.
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 ?