Observer pattern defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
In this pattern, there are many observers (objects) that are observing a particular subject (also an object). Observers want to be notified when there is a change made inside
the subject. So, they register themselves for that subject. When they lose interest in the
subject, they simply unregister from the subject.
Observer Pattern Example
Let’s start with the problem statement,
The below code is a stock simulator that contains a list of dummy stock data. Each stock contains a name and price that we can monitor.
Now you don’t have to know the code for the stock simulator, it’s only going to be here to prove a point.
Here’s my problem, if look at the program we can say that we have two different activity. One activity is checking for the Microsoft price and the other is checking for the google price.
Although they both are independent of each other they are occurring in the same program. If for some reason we want to monitor a new stock we have to update the main program and add some lines like below code,
Now, The observer pattern that allows us to do is separate the monitoring aspect of the stock data from the action of reading the stock data from the stock simulator.
Let’s go step by step and implement the observer pattern for the above problem,
First, we will define a generic interface for observers (subscribers) specifying how they should be updated. In traditional observer pattern, the Update method doesn’t specify any parameters and observers keep a reference of the observable (publisher). But, this approach usually creates a problem like memory leak if we do not clean our observers and observables properly. Hence the below code!
Secondly, we will define a generic observable (subject/publisher) class that uses a generic parameter T as a subject. In traditional observer pattern, usually observable is defined as interface first and then get implemented by concrete subjects. However, by using generics this can be simplified in a single type.
And, finally, we will create our concrete observers for Microsoft and Google stock.
Now our main program can be written in the following way:
Let’s see everything together,
Now, We have discussed before that when observers lose interest in the
subject, they simply unregister from the subject. To implement this all we need to do is update our Subscribe method to return an object that will help us to unregister the passed observer.
Now, here the Unsubscriber<T> is a generic type that maintains the list of observers and the observer to be unsubscribed from the list, i.e the observer we want to remove from the list. Below is the code for the same,
The action of removing the observer from the list of observers unsubscribe the observer from the subject as our subject has reference to the same list.
Also, the code, of removing the observer from the list, is written within the dispose method. This enables us to use the using statement if we want to unsubscribe more elegantly when the operation defined within the using scope is completed.
After making the above changes, our Observable<T> class will look like the code below.
We can go one step further and provide unsubscribe functionality to our observers too. As this will require some implementation we will make our observer as an abstract class instead of an interface.
Here all we did is created a Subscribe method that takes an observable and pass current observer object to its Subscribe method and keep a reference of the cancellation object returned by the method, then we use this object in Unsubscribe method to unsubscribe with the provider.
Now, we can write the client code in the following manner:
above code is more intuitive, instead of,
Also, we can now do this in the client code,
Push And Pull Mechanism Observer Pattern
Now,
When implementing the Observer pattern, there are two main approaches to consider: the ‘push’ model and the ‘pull’ model.
In the ‘push’ model, the subject (i.e. the Observable) sends the observer on notification all the data it will need. The observer doesn’t need to query the subject for information. In the ‘pull’ model, the subject merely notifies the observer that something happened, and the observer queries the subject based to get the information it needs.
Please note,
In both mechanisms, it is always the responsibility of an Observable object to notify all the subscribed observers, the difference lies whether the observer gets the exact data it wants (Push) or it has to extract the required data (Pull).
Let’s discuss the pros and cons of both approaches:
Push
The main advantage of the ‘push’ model is the lower coupling between the observer and the subject. The observer doesn’t need to know anything about the subject to query it. If it needed to, we’d need to do one of the following: A- do downcast on the side of the observer to invoke class-specific get methods on the subject. This is bad. B- make the Observable interface more class-specific, offering specific get methods, thus making the relationship between the observer and subject less general and making things more coupled.
By implementing the ‘push’ model, we avoid all of this.
However, the disadvantage is less flexibility: the subject may not always know what exact information the observers need to send it to them. This will often mean more specific Observer interfaces, such as AgeObserver that are notified when the ‘age’ of the subject is changed, and HeightObserver which are sent the current height of the subject on the notification.
This is one option. The other is the subject sending a whole lot of information encapsulated in an Info object of some sort and have the observers query it from there. But again, we can’t be sure we’re sending the correct info. So it’s either this or forcing the observers to implement more specific Observer interfaces, which tightens the coupling on the observer’s side.
Pull
The main disadvantages of the ‘pull’ model are that the observers would have to know things about the subject to query the right information, which leads A- to downcasting (ugly), or B- favorably to more specific Observable interfaces, that offer more specific accessor methods. For example AgeObservable offers a getAge() method.
The advantage of this is more flexibility. Each observer can decide for itself what to query, without relying on the subject to send the correct information.
Reactive Extensions for .NET
The push model implemented by Reactive Extensions for .NET and is represented by the two interfaces IObservable<T> and IObserver<T>. These interfaces are provided by .NET Framework 4.0 base class library.
You can implement them too in our existing classes like this:
From the above code, you may have noticed, instead of Notify method IObserver relies on OnNext method. The thing is reactive programming represents asynchronous and event-based programs using observable sequences. Reactive Extensions also represents data sequences as observable sequences. An application can subscribe to these observable sequences to receive asynchronous notifications as new data arrive.
In addition to implementing the observer design pattern, you may love to explore libraries that are built using the IObservable<T> and IObserver<T> interfaces. For example, Reactive Extensions for .NET consist of a set of extension methods and LINQ standard sequence operators to support asynchronous programming.
Note: Typically, a Observable implements the Subscribe method by adding a particular observer to a subscriber list that is represented by a collection object, and it implements the Dispose method by removing a particular observer from the subscriber list. So, It could happen that the provider and observer may both try to remove the same member from the list. Because of this possibility, both the Subscribe and Dispose methods should be thread-safe. Typically, this involves using a concurrent collection or a lock. Implementations that are not thread-safe should explicitly document that they are not.
Delegates And Events In C#
Now, In C# you can implement the same idea of observer pattern using Delegates and Events which is really more concise and elegant way of writing this pattern.
An event is a special kind of delegate that facilitates event-driven programming. Events are class members that cannot be called outside of the class regardless of their access specifier. So, for example, an event declared to be public would allow other classes the use of += and -= on the event, but firing the event (i.e. invoking the delegate) is only allowed in the class containing the event.
Typically, an event is created in the subject/observables and registration of observers is made through the delegate callback mechanism. Observers provide the delegate callback implementation that would be called by the subject when the event is raised.
When an abstraction has two aspects, one dependent on the
other. Encapsulating these aspects in separate objects lets you vary
and reuse them independently.
When a change to one object requires changing others, and 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. In other words, you don’t want
these objects tightly coupled.
Note: You can download the complete solution demo from my github repository.
Further Reading
Observer Design Pattern Best Practices - In the .NET Framework, the observer design pattern is implemented using the IObservable<T> and IObserver<T> interfaces. This post describes the best practices that developers should follow when implementing the observer design pattern using these interfaces.
Lesson 07.3: Sending Messages from the ViewModel to the View by Scott Lilly - This is a lesson from Scott’s tutorial - ‘Learn C# by Building a Simple RPG’. In this lesson, Scott creates a way to send messages from the GameSession (ViewModel), to the UI (View). He does this by having the ViewModel “raise an event”, and have the View “subscribe” to that event.
Observer by Bob Nystrom - This is a chapter from Bob’s book ‘Game Programming Patterns’ that explains the Observer pattern from a game developer perspective.
Subscribe to Code with Shadman
Get the latest posts delivered right to your inbox