Observer Design Pattern: Behavioral patterns

Share the Article

What is Observer Design Pattern

Observer design patttern is a type of behavioral pattern which is mainly used when state change of one object, impacts other objects state or behavior. In other words, when one object changes then it induces other objects to take some action. In such cases, the observer pattern is the best fit.

This pattern works on publisher-subscriber principle as below:

Subscriber

Objects that need to monitor specific object. These objects will subscribe for event or state change notification.

Publisher

This is the monitored object. Once it changes it will publish or notify all subscribed objects.

Why

Let us try to understand the need of Observer pattern by taking an example of a mobile application whose job is to play songs. So, whenever, the user select some new song, the application needs to inform or update other components about new song selection.

Below are the objects that need to monitor the song object state:

  • Screen object – showing new song details.
  • Audio speaker object – playing new song.
  • Icon object – showing new song icon.

Sample application without using Observer Design Pattern

One simple way of implementing above application is :

  • Firstly, create all objects.
  • Secondly – on song object state change inform all other objects.

Below is the sample application code without Observer pattern –

#include<iostream> //main header using namespace std;//for namespace class songs { public: void selectnewsong() { cout<<"new song selected"<<endl; } }; class screen { public: void updateScreen() { cout<<"new song data"<<endl; } }; class icon { public: void updateIcon() { cout<<"new Icon loaded"<<endl; } }; class AudioSpeaker { public: void UpdateSong() { cout<<" new song playing"<<endl; } }; int main() //Client code { songs so1; screen s1; icon i1; AudioSpeaker A1; so1.selectnewsong(); s1.updateScreen(); i1.updateIcon(); A1.UpdateSong(); return 0; }

In this example, clearly, the client is directly interacting with all objects. Hence, the client is keeping track of all dependent objects and calling update function for all these objects.

Suppose, if in future, more objects get added, then client need to track them also. Any changes in songs application may impact full client logic.

In summary, above design application is not at all open for modification. In order to solve above problems Observer pattern is the best fit.

How

Lets us try to update above application with Observer design pattern. We need to follow below rules for Observer design pattern:

Identify the monitored and observer component

For the above application

  • Song Class – Monitored component.
  • Screen, Icon and Audio Speaker – Observer Component.

Create the Song monitor and Song Observer classes. Derive all observer component such as Screen, Icon and Audio from Song Observer class.

class SongObserver { }; class Screen: public SongObserver { }; class Icon : public SongObserver { }; class SongMonitor { }

Embed all observer objects inside Monitor class

Embed Song Observer objects inside Song Monitor class. Expose attachSongObserver( ) interface for subscribing observer within monitor class.

class SongMonitor { vector<SongObserver*> m_so; public: void attachSongObserver( SongObserver* so) };

Implement subscribe in observer class

Try to subscribe Observer Class objects during its initialization.

class SongObserver { public: SongObserver(SongMonitor *sm) { sm->attachSongObserver(this); } };

Implement notify method in monitored class

The monitored class shall notify or inform to all observer classes. For instance, on new song selection, the notify shall iterate over all song observer objects. Thus, it will call update observer.

void SongMonitor::selectnewsong() { cout<<"new song selected"<<endl; for ( int i = 0; i < m_so.size(); i++ ) { m_so[i]->updateObserver(); } }

UML Diagram for observer design pattern

Observer design pattern

Application using Observer Design Pattern

Below is the updated code for above application with Observer design pattern:

#include<iostream> //main header #include<vector> //for vector using namespace std;//for namespace class SongObserver; //Forward Declaration class SongMonitor //Publisher { vector<SongObserver*> m_so; public: void attachSongObserver( SongObserver* so) { m_so.push_back(so); } void selectnewsong(); }; class SongObserver //Subscriber { public: SongObserver( SongMonitor *sm) { sm->attachSongObserver(this); } virtual void updateObserver() =0; }; class screen: public SongObserver { public: screen( SongMonitor *sm):SongObserver(sm) { } void updateObserver() { cout<<"Update new song data in Screen"<<endl; } }; class icon : public SongObserver { public: icon( SongMonitor *sm):SongObserver(sm) { } void updateObserver() { cout<<"New Icon loaded"<<endl; } }; class AudioSpeaker: public SongObserver { public: AudioSpeaker( SongMonitor *sm):SongObserver(sm) { } void updateObserver() { cout<<" New song playing"<<endl; } }; void SongMonitor::selectnewsong() { cout<<"new song selected"<<endl; for ( int i = 0; i < m_so.size(); i++ ) { m_so[i]->updateObserver(); } } int main() { SongMonitor *sm = new SongMonitor; SongObserver *screenObserver = new screen(sm); SongObserver* iconObserver = new icon(sm); SongObserver* audioObserver = new AudioSpeaker(sm); sm->selectnewsong(); delete sm; delete screenObserver; delete iconObserver; delete audioObserver; return 0; }

Clearly, now client not longer directly interacts with all the Observer objects. Client is just calling Monitored object select song interface. Therefore, any changes in Observer object will not impact client.

In Summary, if we want to add new object to observe the state, then just initialize it. On initialization it will subscribe to the Monitored object. Therefore, with Observer pattern it is very easy and simple to monitor the objects. Whenever we have such use cases, where we want to monitor and notify state changes, Observer pattern is the best option.

Pros and Cons of Observer Design Pattern

Pros

  • Firstly, the addition and deletion of objects is very easy and will not impact client.
  • Secondly, the client application remains very simple or less complex.

Cons

  • Firstly, we need to design publish-subscribe principle very carefully.
  • Any issue in design will impact full application.

Main Funda: Observer Design Pattern enables observers to monitor the state of publisher.

Advanced C++ Topics

Abstract Factory Design Pattern
Singleton Design Pattern
Factory Method Design Pattern
Builder Design Pattern
Adapter Design Pattern
Prototype Design Pattern
Facade Design Pattern
Bridge Design Pattern
Composite Design Pattern
Decorator Design Pattern
Template Design Pattern
Strategy Design Pattern
Visitor Design Pattern


Share the Article

Leave a Reply

Your email address will not be published. Required fields are marked *