Observer Pattern in C#
Tags: beginners, programming, tutorial, csharp
Published: 2022-09-13 07:20:20

_Originally posted [here](https://dfordebugging.wordpress.com/2022/09/13/observer-pattern-in-c/)_

The **Observer** is a behavioural design pattern that lets us define a subscription mechanism to notify multiple objects about any events that happen to the entity they're observing.

The **Observer** pattern allows objects to notify their observers when their internal state changes, meaning that a single class has to be aware of the entities that observe it. It also needs to communicate to those observers about alterations in the subject's state. Further, the observers should be notified automatically.

You can find the example code of this post, on [GitHub](https://github.com/Kalkwst/DesignPatterns)

## Conceptualizing the Problem

Let's imagine that we have an online store. We have the entities `Customer` and `Store`. One of our customers has a very peculiar taste and is interested in a particular brand of super universal remotes. These remotes should be available in our store very soon.

The customer could visit the store every day and check product availability. But while the product is still en route, most of these trips would be pointless.

On the other hand, the store could send tons of emails to all customers each time a new product becomes available, saving some customers from endless trips to the store. At the same time, it'd upset other customers who aren't interested in new products.

Now we are in a conflict. Either our customers will have to waste time checking product availability, or the store will have to waste resources notifying the wrong customers.

An object with an observed state is commonly known as a *subject*, but since it notifies other objects about state changes, we'll call it a *publisher*. All other objects that want to track changes to the publisher's state are called *subscribers*.

The **Observer** pattern suggests that we add a subscription mechanism to the publisher class so individual objects can subscribe to or unsubscribe from a stream of events sent by the publisher. 

In reality, this mechanism consists of an array field for storing a list of references to the subscriber objects and several public methods which allow adding subscribers to and removing them from that list.

![Observer-Publisher Diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/saazyt5qv0olmdteo1kf.PNG)

Now the publisher goes over to its subscribers and calls their specific notification method.

Real-world applications might have dozens of different subscriber classes interested in tracking events of the same publisher class. We wouldn't want to couple the publisher to all of those classes. 

Thus, it's crucial that all subscribers implement the same interface and that the publisher only communicates with them exclusively via that interface. The interface should declare the notification method along with a set of parameters that the publisher can use to pass some contextual data along with the notification.

If our application uses several different publisher classes, we can make all publishers use the same interface. This interface would only need to describe a few subscription methods. The interface would allow subscribers to observe the publishers' states without coupling to their concrete implementations.

## Structuring the Observer Pattern

In its base implementation, the Observer pattern has four subscribers:

![Observer Class Diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xx4jsdz6bkpe1hepqp19.PNG)

- **Publisher**: The **Publisher** issues events of interest to other objects. The events occur when the publisher changes its state or executes some behaviour. Publishers contain the subscription infrastructure that lest new subscribers join and current subscribers leave the list. When a new event happens, the publisher goes oven the subscription list and calls the notification method declared in the subscriber interface on each subscriber object.
- **Subscriber**: The **Subscriber** interface declares the notification interface. In most cases, it consists of a single `Update` method. The method may have several parameters that let the publisher pass some event details along with the update. 
- **Concrete Subscriber**: The **Concrete Subscribers** perform some actions in response to notifications issued by the publisher. All of these classes must implement the same interface so the publisher isn't coupled to concrete classes. Usually, subscribers need some contextual information to handle the update correctly. For that reason, publishers often pass some context data as arguments for the notification method. The publisher can pass itself as an argument, letting the subscriber fetch any required data directly.
- **Client**: The **Client** creates publisher and subscriber objects separately and then registers subscribers for published objects.

To demonstrate our observer, let's imagine that we are going to implement a system that tracks the fluctuating prices of goods in our local farmer's markets.

On some days, the goods will be more expensive than on other days, due to factors like the season, the size of the harvest or the quality of the goods themselves. Further, we need to allow restaurants to watch the prices and place an order when the price of a particular item falls below a specified threshold, which is different for each restaurant.

First, let's define our **Subject** participant abstract class `Goods`, which needs to implement the methods by which it can attach or detach observers and keeps track of a certain good's current price:

```csharp
using Observer.Observers;

namespace Observer.Subjects
{
    /// <summary>
    /// The Subject abstract class
    /// </summary>
    public abstract class Goods
    {
        private double pricePerKilo;
        private List<IRestaurant> restaurants = new List<IRestaurant>();

        protected Goods(double pricePerKilo)
        {
            this.pricePerKilo = pricePerKilo;
        }

        public void Attach(IRestaurant restaurant)
        {
            restaurants.Add(restaurant);
        }

        public void Detach(IRestaurant restaurant)
        {
            restaurants.Remove(restaurant);
        }

        public void Notify()
        {
            foreach(IRestaurant restaurant in restaurants)
            {
                restaurant.Update(this);
            }

            Console.WriteLine();
        }

        public double PricePerKilo
        {
            get { return pricePerKilo; }
            set
            {
                if(pricePerKilo != value)
                {
                    pricePerKilo = value;
                    Notify();
                }
            }
        }
    }
}
```

We also need some **ConcreteSubject**s which represent the price of specific products, in this case, `Cucumber` and `Mutton`.

```csharp
namespace Observer.Subjects
{
    /// <summary>
    /// A ConcreteSubject class
    /// </summary>
    public class Cucumbers : Goods
    {
        public Cucumbers(double pricePerKilo) : base(pricePerKilo)
        {
        }
    }
}
```

```csharp
namespace Observer.Subjects
{
    /// <summary>
    /// A ConcreteSubject class
    /// </summary>
    public class Mutton : Goods
    {
        public Mutton(double pricePerKilo) : base(pricePerKilo)
        {
        }
    }
}
```

Now we can define our **Observer** participant. Remember that restaurants want to observe the vegetable prices, so our *Observer* will naturally be an interface `IRestaurant`, and this interface must define a method by which its implementors can be updated:

```csharp
using Observer.Subjects;

namespace Observer.Observers
{
    public interface IRestaurant
    {
        public void Update(Goods goods);
    }
}
```

Finally, we need our **ConcreteObserver** class, which represents specific restaurants. This class must implement the `Update()` method from `IRestaurant`:

```csharp
using Observer.Subjects;

namespace Observer.Observers
{
    /// <summary>
    /// The ConcreteObserver class
    /// </summary>
    public class Restaurant : IRestaurant
    {
        private string name;
        private Dictionary<Goods, double> goodsThresholds;

        public Restaurant(string name)
        {
            this.name = name;
            goodsThresholds = new Dictionary<Goods, double>();
        }

        public void AddGoodsThreshold(Goods good, double threshold)
        {
            goodsThresholds.Add(good, threshold);
        }

        public void Update(Goods goods)
        {
            Console.WriteLine($"Notified {name} of {goods.GetType().Name}'s price change to {Math.Round(goods.PricePerKilo, 2)} per kilo");

            if (goods.PricePerKilo < goodsThresholds[goods])
                Console.WriteLine($"{name} wants to buy some {goods.GetType().Name}!");
        }
    }
}
```

The restaurants will only buy goods if the price dips below a certain threshold amount, which differs per restaurant.

To put this all together, in our `Main()` method we can define a few restaurants that want to observe the price of cucumbers and mutton, and then fluctuate the price:

```csharp
using Observer.Observers;
using Observer.Subjects;

Restaurant bobsBurgers = new Restaurant("Bob's Burgers");
Restaurant krustyBurger = new Restaurant("Krusty Burger");
Restaurant carrotPalace = new Restaurant("Carrot Palace");

Cucumbers cucumbers = new Cucumbers(0.82);
Mutton mutton = new Mutton(12.9);

bobsBurgers.AddGoodsThreshold(cucumbers, 0.77);
bobsBurgers.AddGoodsThreshold(mutton, 10.8);

krustyBurger.AddGoodsThreshold(mutton, 8.2);

carrotPalace.AddGoodsThreshold(cucumbers, 0.89);

cucumbers.Attach(bobsBurgers);
cucumbers.Attach(carrotPalace);

mutton.Attach(krustyBurger);
mutton.Attach(bobsBurgers);

// Create price fluctuation
cucumbers.PricePerKilo = 0.78;
cucumbers.PricePerKilo = 0.65;
cucumbers.PricePerKilo = 1.02;

mutton.PricePerKilo = 12.0;
mutton.PricePerKilo = 10.2;
mutton.PricePerKilo = 6.81;

Console.ReadKey();
```

If we run the application, we will see that as the price changes, the restaurants get notified, and if the price drops below each restaurant's threshold, that restaurant wants to place an order. Below is the output:

![Observer Demo Output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ac5eep338ztkaulty5e3.PNG)

As you can see, the subject-object (`Cucumbers` and `Mutton`) automatically notify the observer restaurants of their price changes. which can then decide what to do with that information.

## Difference Between Mediator and Observer

The difference between the **Mediator** and the **Observer** pattern is often elusive. In most cases, we can implement either of these patterns; but there are cases where we can implement both.

The primary goal of the *Mediator* is to eliminate dependencies among a set of components. These components instead become dependent on a single mediator object. The primary goal of the *Observer*, on the other hand, is to establish dynamic one-way connections between objects, where some objects act as subordinates of others.

One popular implementation of the _Mediator_ pattern relies on the _Observer_ pattern. The mediator plays the role of the **publisher** and the components act as **subscribers** to the mediator events. When the _Mediator_ is implemented this way, it looks very similar to the _Observer_ pattern.

When you are confused about whether you have a *Mediator* or an *Observer* remember that the *Mediator* can be implemented differently. For example, you can permanently link all components to the same mediator object. This implementation won't resemble the *Observer* pattern but will still be an instance of the *Mediator* pattern.

Now if you have a program where all components are publishers, allowing dynamic connections between each other, you have a distributed set of *Observers*, since there is no centralized *Mediator* object.

## Pros and Cons of Observer Pattern
|||
|:--|:--|
|✔ We can introduce new subscriber classes without having to change the publisher's code, thus satisfying the *Open/Closed Principle*|❌There is no specific order that the subscribers are notified|
|✔ We can establish relations between objects at runtime||

## Relations with Other Patterns
- **Chain of Responsibility**, **Command**, **Mediator** and **Observer** are patterns that address various ways of connecting senders and receivers of requests.
	- The *Chain of Responsibility* pattern passes a request sequentially along a dynamic chain of receivers until one of them handles it
	- The *Command* pattern establishes unidirectional communication channels between senders and receivers
	- The *Mediator* pattern eliminates direct connections between senders and receivers, forcing them to communicate indirectly via the mediator object.
	- The *Observer* pattern lets receivers dynamically subscribe to and unsubscribe from receiving requests.

## Final Thoughts

In this article, we have discussed what is the Observer pattern, when to use it and what are the pros and cons of using this design pattern. We also examined how the Observer pattern relates to other classic design patterns.

The Observer pattern seeks to allow Observer objects to automatically receive notifications (and possibly change their own state) when a Subject class changes its state. In short, should the Subject change, the Observers will be notified about said change.

The Observer design pattern is helpful in many ways and is quite flexible if appropriately used. However, it's worth noting that the Observer pattern, along with the rest of the design patterns presented by the Gang of Four, is not a panacea or a be-all-end-all solution when designing an application. Once again it's up to the engineers to consider when to use a specific pattern. After all these patterns are useful when used as a precision tool, not a sledgehammer.