Monday, July 22, 2024 13:25

Table of contents >> Delegates, Lambda Expressions, Events > Observer Pattern

Observer Pattern

According to Microsoft, observer pattern is a behavioral design that allows one object to notify other objects about changes in its state.

Many beginner programmers (and even more experienced ones) have a hard time understanding the link between delegates and events, and the core upon which this link is built is represented precisely by the observer pattern. To make this concept easy to understand, so you can learn the transition to events easier, let’s take a simple example. Let’s imagine that we want to implement a system that will alert cars when a train is coming, so that they stop. The first building block of this system will be represented by a class named TrainSignal:

There is nothing complicated about my class: I added an Action, TrainsAreComing, and remember, an Action is just a delegate that takes between 0 and 16 parameters and returns void. This will represent our train signal. Finally, I added a public method named HereComesATrain(), that will perform all the necessary actions when a train is coming, and also inform anyone that is interested in the train coming, by invoking the TrainsAreComing delegate.

The next step is to declare the objects that are actually interested in the fact of a train coming, so, I will add a Car class:

In my Car class, I have an overload constructor that accepts a TrainSignal instance, and inside this constructor I am adding a method named StopTheCar() to the delegate chain of TrainsAreComing. This can also be understood as “I am subscribing my StopTheCar() method to the TrainsAreComing delegate, so that when this delegate is invoked, my method will be called too”, or simply “hey, add me to the list of subscribers of this delegate”.

And this is precisely the .NET way of doing the observer pattern, by subscribing our methods to the chain of methods of a delegate, whenever that delegate will be invoked, all the methods that subscribed to it will get called, so, they will “observe” that the delegate was invoked. In my example, all the Car instances that will subscribe to TrainsAreComing delegate will observe when this delegate will be invoked (when the train signal will be triggered and all the subscribing methods will be notified).

Now, all it remains to be done is to actually put this whole system to work:

First thing to remember is that a delegate keeps track not only of the method that it will later call, but also of the object that that method belongs to. I explained in the lesson about delegates that they have two important properties: Method and Target. For this reason, I don’t actually have to declare a name for my Car instances, I can instantiate them anonymously, using the new operator directly. Since they all subscribe to TrainsAreComing delegate inside their constructor, the delegate will remember each instance that subscribed to it.

Next, notice that when I am calling HereComesATrain() method, it will invoke the delegate, which means that the delegate will call any StopTheCar() method of any Car that subscribed to it, effectively notifying each subscriber.

This is the output that proves the fact that all our 5 subscriber Car instances stopped when the train signal delegate was invoked:

Observer pattern in C#

Tags: , , , , ,

Leave a Reply

Follow the white rabbit