- Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and update automatically.
- The observer pattern describes how to establish a one-to-many relationship.
- The key objects are subject and observer and the subject may have any number of dependent observers. All the observers are notified whenever the subject undergoes a change in state.
- The observers will query the subject to synchronize their state with the subject’s state.
- This interaction is also known as publish-subscribe. The subject is the publisher and the observer is the subscriber.
#include<iostream>
#include<string>
#include<list>
using namespace std;
//Forward Declaration
class Stock;
// The 'Observer' interface
class IInvestor
{
public:
virtual void Update(Stock* stock){};
};
// The 'Subject' abstract class
class Stock
{
public:
Stock(string symbol, double price) : symbol_(symbol), price_(price) { }
void Attach(IInvestor* investor)
{
investors_.push_back(investor);
}
void Detach(IInvestor* investor)
{
investors_.remove(investor);
}
void Notify()
{
list<IInvestor*>::iterator it = investors_.begin();
while(it != investors_.end())
{
(*it)->Update(this); ++it;
}
}
double GetPrice(void)
{
return price_;
}
void SetPrice(double price)
{
price_ = price;
Notify();
}
string GetSymbol(void)
{
return symbol_;
}
private:
string symbol_;
double price_;
list<IInvestor*> investors_;
Stock();
};
// The 'ConcreteSubject' class
class Company : public Stock
{
public:
Company(string name, string symbol, double price) : name_(name), Stock(symbol, price) {}
string GetName(void)
{
return name_;
}
private:
string name_;
};
// The 'ConcreteObserver' class
class Investor : public IInvestor
{
public:
Investor(string name) : name_(name){}
void Update(Stock* stock)
{
cout<<"Notified "<<name_<<" about "<<(reinterpret_cast<Company*>(stock))->GetName()<<" change to "<<stock->GetSymbol()<<stock->GetPrice()<<endl;
}
private:
string name_;
Investor();
};
//The Main method
int main()
{
Company* c1 = new Company("Google", "$", 123.0);
cout<<"Created company Google with Stock Price 123.0\n"<<endl;
Investor* i1 = new Investor("Billy");
c1->Attach(i1);
cout<<"Created investor Billy following Google\n"<<endl;
c1->SetPrice(125.0);
Investor* i2 = new Investor("Timmy");
c1->Attach(i2);
Investor* i3 = new Investor("Lenny");
c1->Attach(i3);
cout<<"\nCreated investor Timmy and Lenny following Google\n"<<endl;
c1->SetPrice(145.0);
c1->Detach(i1);
c1->Detach(i3);
cout<<"\nInvestor Billy and Lenny not interested in Google anymore\n"<<endl;
c1->SetPrice(165.0);
delete i1;
delete i2;
delete i3;
delete c1;
return 0;
}
Advantages:
The subject only knows about the list of observers which conform to the interface of the abstract observer. It does not know the concrete class of any observer. This promotes loose coupling.
The subject need not specify the receiver of the notification. It gives a complete freedom of adding and removing observers dynamically.
Disadvantages:
Observers don’t have any knowledge of each other’s presence. A simple operation on the subject may cause a cascade of unnecessary updates on the observers resulting in unnecessary operations.
When to use the pattern :
The observer pattern can be used for any of the following situations:
When a change to one object must reflect in other objects, without keeping the objects tightly coupled.
When an object should be able to notify other objects without worrying about who these objects are.