Wednesday 17 November 2010

C++ example of Observer Design Pattern

Definition: Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

Observers register themselves with the Subject as they are created. Whenever the Subject changes, it broadcasts to all registered Observers that it has changed.


The Observer defines a one-to-many relationship so that when one object changes state, the others are notified and updated automatically. Some auctions demonstrate this pattern. Each bidder possesses a numbered paddle that is used to indicate a bid. The auctioneer starts the bidding, and “observes” when a paddle is raised to accept the bid. The acceptance of the bid changes the bid price which is broadcast to all of the bidders in the form of a new bid.

Observer is a very popular pattern and its frequency of use is very high.

The following is an example of Observer Design Pattern:




//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
//Observer is part of Behavioral Patterns
//Behavioral Patterns deal with dynamic interactions among societies of classes and objects
//An Observer is a way of notifying change to a number of classes.

//We will take an example of Stock Price where, Observers can register to be told about
//the stock price change of a company

#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;
}



The output is as follows:
Further Reading:




3 comments:

  1. Thanks! It was very usefull!

    ReplyDelete
  2. Great! What if instead of setting a whole new price as in

    c1->SetPrice(165.0);

    I wanted to just add $20 to the current value? how would I do that?
    Thanks

    ReplyDelete
  3. it's gud one but better you give more input in terms of push and pull mode of observer pattern(than it will be more worthful for a newbie.

    ReplyDelete