Design Pattern means that “we had some problem then we found the solution and gave name to this solution” and observer is also one of the solution so we need to find the problem that observer has solved and how ?
This design pattern comes under Behavioral Category (It tells that how objects are communicating with each other (objects have been created already)).
================================================================
C++ Observer Design Pattern :
Standard Definition:
It defines a one to many dependency between objects so when one object changes state, all its dependent are notified and updated automatically.
Problem:
We want to monitor specific state of one object but don’t want to continuous polling.
Solution:
Instead of polling we can register in that object and that object will notify us when that specific state occur and we get the specific state without polling, this solution called as “observer design pattern“. This pattern is called as “publisher and subscriber“.
When we will use observer pattern:
- When we want to monitor some state of an object then we will use observer design patter. It is “one to many” so one object will be monitored by one or many object.
- Second scenario rotate the coin, one object has changed its state and want to broadcast or update to its dependent objects. We don’t know the number of dependent objects.
- when there are 2 scenario and one dependent on other, encapsulate each in object and use them independently.
Class Diagram:
This is “one to many communication”. one is the object that is being monitored and many are the other object they want to monitor.
Subject: This is one independent object that is being monitored. This is publisher of notification to all dependent observers.
Observer object/objects: They want to monitor. They all need to subscribe in subject.
Advantage:
- No need to do polling (polling is expensive operation so this should be avoided).
- Loose coupling (subject and observers are not tight coupled, there is separate hierarchy of observers (receivers) so we can process the data in different way).
- We can add new observer at any time without polluting existing code.
- This design allow subject and object vary independently, we can reuse subject and observer.
Disadvantage:
- If observer objects are large in number(many observers) then this pattern will become complex.
- Frequent changes in subject can cause the performance problem (bombarding of “update()” should not happen).
- If subject changes then it effect observer so there is possibility of spurious update (if something wrong changed in subject).
Key Points:
- If observer wants to monitor 2 subject then need to change “update interface” so that both subject can be handled.
- Dangling reference of subject in observer should be avoided.
- Notify can be called by subject or client.
- Notify should be called after setting the state in subject (subject state self consistent).
- Updation of state in observer can be done by push model or pull model.
- push model: Subject will send the detail info as a part of update() API.
- pull model: Subject will send the minimal info to observer, after this observer get the detail info explicitly.
source code with real example:
/* * File:observer.cpp * This file is described the Observer Design Pattern with help of example * This Example will explain How observer pattern works * How to register, deresigter and notify to registered client * Author: Aplha Master * Date: 02 Oct 2021 */ ///////////////////////////////////Header files//////////////////////////////////// #include <iostream> #include <list> #include <thread> #include <chrono> class Observer; // Forward Decleration class Subject { int _m_time; // List to observers, who will be notified when state change std::list<Observer*> _m_list; public: Subject(); ~Subject(); void Attach(Observer*); void Detach(Observer*); void SetState(int); int GetState(); private: Subject(const Subject &other) = delete; // Disallow copying void operator=(const Subject &) = delete;// Disallow copying void Notify(); }; class Observer { protected: Subject* _m_sub; public: virtual void Update()=0; }; //Constructor Subject::Subject() { _m_time = 0; } //Destructor Subject::~Subject() { _m_time = 0; if(!_m_list.empty()) { _m_list.clear(); } } //Attach Function is used for registeration and observer will use this fucntion void Subject::Attach(Observer* ob) { _m_list.push_back(ob); } //Detach function is used for de-registeration void Subject::Detach(Observer* ob) { _m_list.remove(ob); } //Notify Function is notify to registered observer when state change void Subject::Notify() { std::list<Observer *>::iterator iterator = _m_list.begin(); while (iterator != _m_list.end()) { (*iterator)->Update(); ++iterator; } } //Set state void Subject::SetState(int t) { _m_time = t; Notify(); } int Subject::GetState() { return _m_time; } class AnalogObserver : public Observer { public: AnalogObserver(Subject * sub) { _m_sub = sub; _m_sub->Attach(this); } ~AnalogObserver() { _m_sub->Detach(this); } void Update() { PrintTime(); } void PrintTime() { std::cout<<"AnalogTimer got notification:"<<_m_sub->GetState()<<std::endl; } }; class DigitalObserver : public Observer { public: DigitalObserver(Subject * sub) { _m_sub = sub; _m_sub->Attach(this); } ~DigitalObserver() { _m_sub->Detach(this); } void Update() { PrintTime(); } void PrintTime() { std::cout<<"DigitalTimer got notification:"<<_m_sub->GetState()<<std::endl; } }; int main() { std::cout<<"In Main"<<std::endl; //Create the Subject Subject sub; //Create the Observers AnalogObserver analogObj(&sub); DigitalObserver digitalObj(&sub); //Change the Subject, Observer should be notified for(int i =1; i<5; i++) { sub.SetState(i); std::this_thread::sleep_for(std::chrono::seconds(1)); } return 0; }
Output:
In Main AnalogTimer got notification:1 DigitalTimer got notification:1 AnalogTimer got notification:2 DigitalTimer got notification:2 AnalogTimer got notification:3 DigitalTimer got notification:3 AnalogTimer got notification:4 DigitalTimer got notification:4
Other scenario:
Subject can also become observer of other subject then we need to take mediator object to make communication between them. I will explain later.