Page 1 of 1

The Listener Pattern The Listener Pattern AKA The Observer Pattern Rate Topic: -----

#1 Styn  Icon User is offline

  • New D.I.C Head
  • member icon

Reputation: 4
  • View blog
  • Posts: 13
  • Joined: 03-December 08

Posted 29 October 2010 - 10:42 AM

The Observer Pattern (aka the listener pattern)

Preface
This article is aimed at more advanced programmers, the example will be in C++ code but since this is a design pattern it is portable to different languages.
You should be fairly familiar with both object orientation and inheritance. Some familiarity with vectors and algorithms is also assumed.
A common problem
There are a lot of cases where you want certain objects to keep tabs on what other objects are doing, or what state they are in. As with most common problems other programs have had this problem before, and have made a solution to it. If there’s one thing a programmer needs to be and that’s lazy. Never do yourself what others have probably done better before.
In this example I am going to pretend to be writing a simple game where the player is a sneaky thief trying to grab a jewel. But the jewel is on a pressure plate. If it is removed it will send a signal to the guards’ PDA’s.
Disclaimer: I will keep the implementation of everything very simple, to not confuse you too much.
General idea
We will be making two abstract classes, an observer (or listener if you prefer that term) and a subject (or caller). (In java or C# you would be using interfaces for this.)
The observers are just chilling (imagine the guards having a cup of tea or something), until the jewel gets lifted of the panel. At that moment a signal is sent to all the guards that have their PDAs with them. (Have been added to the Subject’s observer list.)

Attached Image

Observer
#pragma once

#include <vector>
using namespace std;

class Observee;
//-----------------------------------------------------
// Observer Class			
//-----------------------------------------------------
class Observer
{
public:
	virtual ~Observer();		// Destructor
	virtual void Notify(Observee* observee){};
protected:
//constructor is protected because this class is abstract, it’s only meant to be inherited!
	Observer();
private: 
	// -------------------------
	// Disabling default copy constructor and default 
	// assignment operator.
	// -------------------------
	Observer(const Observer& yRef);	
	Observer& operator=(const Observer& yRef);	
};


The class that inherits Observer needs to implement the virtual Notify(Observee* observee) method. It will be called by the subject when necessary, in the case of our example when the jewel is removed from its place.

Subject
#pragma once

#include "Header.h"
#include <vector>
#include <algorithm>

class Observer;
//-----------------------------------------------------
// Observee Class									
//-----------------------------------------------------
class Observee
{
public:
	
	virtual ~Observee();		//destructor

	bool AddObserver(Observer* observer);
	bool RemoveObserver(Observer* observer);
	bool NotifyObservers();
protected:
	//constructor is protected because this class is abstract, it’s only meant to be inherited!
	Observee();
private: 
	vector<Observer*> m_ObserverVec;
	// -------------------------
	// Disabling default copy constructor and default 
	// assignment operator.
	// -------------------------
	Observee(const Observee& yRef);									
	Observee& operator=(const Observee& yRef);	
};



The Subject (‘Observee’ in the code example) does all the hard work. It keeps track of all observers and notifies them when necessary!
The three methods are fairly easy to understand, their name describes what they do. They return a bool so you can check if the execution went as expected.

//this method adds an observer to the vector of observers
bool Observee::AddObserver( Observer* observer )
{
	vector<Observer*>::iterator temp = find(m_ObserverVec.begin(), m_ObserverVec.end(), observer);
	//Return false if the observer is already in the vector. This is not expected. But there is nothing really wrong either
	if ( temp != m_ObserverVec.end() )
		return false;

	m_ObserverVec.push_back(observer);
	return true;
}

//This method removes an observer from the vector
bool Observee::RemoveObserver( Observer* observer )
{
	vector<Observer*>::iterator temp = find(m_ObserverVec.begin(), m_ObserverVec.end(), observer);
	//Return false if the observer could not be found (and evidently can’t be removed.
	if ( temp == m_ObserverVec.end() )
		return false;
	else
		m_ObserverVec.erase(remove(m_ObserverVec.begin(), m_ObserverVec.end(), observer));
	return true;
		
	
}

//This Method is very important, it triggers all Notify() methods of all observers.
//The specific code in each class that inherits from observer will be executed
bool Observee::NotifyObservers()
{
	for_each(m_ObserverVec.begin(), m_ObserverVec.end(), Notifier(this));
	//Return false if there are no observers in the vector
	return (m_ObserverVec.size() > 0);
}


Implementation
The next thing to do is test out our two classes. We’ll be doing this in a simple win32 console program. This will include a Jewel class (the Subject), a Guard class, and a SecurityDoor class. The last two classes will be our observers.

The Jewel class
// We need the Observee class to make this observeable
#include "Observee.h"
//-----------------------------------------------------
// Jewel Class					
//-----------------------------------------------------
class Jewel : public Observee
{
public:
	Jewel();				// Constructor
	virtual ~Jewel();		// Destructor
};


This is really all that’s needed to make the Jewel Observable!

Guard Class
//Including the Observer class
#include "Observer.h"
#include <iostream> // We want to print text to the console, so we’ll need this
using namespace std;
//-----------------------------------------------------
// Guard Class									
//-----------------------------------------------------
class Guard : public Observer //The guard is an observer!
{
public:
	Guard(string name);				// Constructor
	virtual ~Guard();		// Destructor

	// The Print() method just prints something to the screen
	void Print() const;
	virtual void Notify(Observee* observee); 
//The implementation of the Notify method will determine what happens when the guard is notified

private: 
	string m_Name;

	// -------------------------
	// Disabling default copy constructor and default 
	// assignment operator.
	// -------------------------
	Guard(const Guard& yRef);									Guard& operator=(const Guard& yRef);	
};


For details and a sample program you can download the project included at the end.

Summary
So to wrap things up, the Observer/Subject pattern connects classes in a one-to-many relation. It does this trough loose coupling, an important Design Principle.
The class at the ‘one’ end of the relation (the subject) can send a message to all ‘Observers’ that are subscribed to that particular Subject.
It’s also possible to trigger a certain observer with different kinds of Subjects, you just subscribe the observer to different subjects.

Example Project
Seems that I can't attach .rar files, so I'll upload it to a file sharing service. The rar contains a Visual studio 2008 project with all of the above code, and some more.
Sample Project Here

References
  • Head First Design Patterns (Freeman)
  • C++ Coding Standards (Sutter & Alexandrescu)


Is This A Good Question/Topic? 3
  • +

Replies To: The Listener Pattern

#2 stayscrisp  Icon User is offline

  • フカユ
  • member icon

Reputation: 999
  • View blog
  • Posts: 4,179
  • Joined: 14-February 08

Posted 30 October 2010 - 01:43 PM

This is a great tutorial, I'm using a similar method to send messages between NPC's for an AI project. Really well explained! Nice work!
Was This Post Helpful? 0
  • +
  • -

#3 Styn  Icon User is offline

  • New D.I.C Head
  • member icon

Reputation: 4
  • View blog
  • Posts: 13
  • Joined: 03-December 08

Posted 31 October 2010 - 01:27 PM

Thanks for the compliments! If anyone has a suggestion for a next tutorial I'd be happy to have a go at it!
Was This Post Helpful? 0
  • +
  • -

#4 Anarion  Icon User is offline

  • The Persian Coder
  • member icon

Reputation: 282
  • View blog
  • Posts: 1,456
  • Joined: 16-May 09

Posted 05 November 2010 - 08:34 AM

In order to make your class abstract, you can turn (at least)one virtual function into a pure virtual function:
class Observer
{
public:
	virtual ~Observer();		// Destructor
	virtual void Notify(Observee* observee)=0; //Pure Virtual
	Observer();
private: 
	// -------------------------
	// Disabling default copy constructor and default 
	// assignment operator.
	// -------------------------
	Observer(const Observer& yRef);	
	Observer& operator=(const Observer& yRef);	
};

This way, you also make sure derived classes are allowed only if they implement all pure virtual functions of base. I guess this form of abstract classes is better in general, as it provides better control over the virtual functions(forcing implementation in derived classes).

This post has been edited by Anarion: 05 November 2010 - 08:36 AM

Was This Post Helpful? 1
  • +
  • -

#5 Styn  Icon User is offline

  • New D.I.C Head
  • member icon

Reputation: 4
  • View blog
  • Posts: 13
  • Joined: 03-December 08

Posted 06 November 2010 - 02:49 AM

Very valuable addition! Mind if I add it to the tutorial itself?
Was This Post Helpful? 0
  • +
  • -

#6 Anarion  Icon User is offline

  • The Persian Coder
  • member icon

Reputation: 282
  • View blog
  • Posts: 1,456
  • Joined: 16-May 09

Posted 07 November 2010 - 09:49 AM

View PostStyn, on 06 November 2010 - 12:19 PM, said:

Very valuable addition! Mind if I add it to the tutorial itself?

Sure, feel free to add it :)
Was This Post Helpful? 0
  • +
  • -

#7 adrainsean  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 01-March 11

Posted 01 March 2011 - 01:53 AM

hey this works perfectly very well done ..but i had some doubts with the code flow ...

i mean in the Notifier class , why has the operator being overloaded()??
and how does it get called (i mean by whom....., gives it the observer pointer as parameter ??)

i hope i was clear in my question

i see the constructor of the notifier class getting called via for_each loop for all registered listeners in vector, but how in turn the overloaded () is called has been baffling me ...


here are the code stubs
the notifier class
class Notifier
{
public:
	Notifier(Observee* observee) : m_pObservee(observee)
	{}

	void operator()(Observer* observer)
	{
		observer->Notify(m_pObservee);
	}

private:
	Observee* m_pObservee;
}; 




and the method from which this notifier class is called.
bool Observee::NotifyObservers()
{
	for_each(m_ObserverVec.begin(), m_ObserverVec.end(), Notifier(this));

	return (m_ObserverVec.size() > 0);
}



my doubt again >> how is the overloaded function of notifier called ?? who calls it and how is observer pointer provided to it as parameter ??
Was This Post Helpful? 0
  • +
  • -

#8 Styn  Icon User is offline

  • New D.I.C Head
  • member icon

Reputation: 4
  • View blog
  • Posts: 13
  • Joined: 03-December 08

Posted 01 March 2011 - 02:24 AM

I think you need to look at how for_each works. It takes a specific function (or object with overloaded () operator) and calls it for each (hence, for_each ;)) object in the collection.
for_each( <first iterator>, <last iterator>, <function(params)> )



The Notifier object gets passed the observee as a construction parameter.

So for each Observee pointer in m_ObserverVec the ()operator of the Notifier object gets called. (It is required that we make an object of this class first!)

I hope this helps you out a little. If you need more info on for_each click here

Some more info on functors here

This post has been edited by Styn: 01 March 2011 - 05:23 AM

Was This Post Helpful? 0
  • +
  • -

#9 adrainsean  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 01-March 11

Posted 01 March 2011 - 04:53 AM

ohh i see well i all this time i was thinking some how the constructor calls the overloaded () and didnt pay much attention to for_each ...just taking it as a wrapper for normal for loop

ya what you explained makes sense ...so a notifier object is created with "this" and then () overloaded operator is called with different observer pointer taken iteratively from the vector ... did i get it right ??
Was This Post Helpful? 0
  • +
  • -

#10 adrainsean  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 01-March 11

Posted 01 March 2011 - 05:11 AM

STYN ...i have a another doubt.... why is it that you have disabled copy constructor and assignment operator ??
i didnt get the purpose of it
Was This Post Helpful? 0
  • +
  • -

#11 Styn  Icon User is offline

  • New D.I.C Head
  • member icon

Reputation: 4
  • View blog
  • Posts: 13
  • Joined: 03-December 08

Posted 01 March 2011 - 05:27 AM

View Postadrainsean, on 01 March 2011 - 04:53 AM, said:

ya what you explained makes sense ...so a notifier object is created with "this" and then () overloaded operator is called with different observer pointer taken iteratively from the vector ... did i get it right ??

Yes this seems to be correct. I did explain it a little confusingly in my previous post, so I editted it a bit.


View Postadrainsean, on 01 March 2011 - 05:11 AM, said:

STYN ...i have a another doubt.... why is it that you have disabled copy constructor and assignment operator ??
i didnt get the purpose of it


This is just for safety, I do this with all my classes. If I need them I must first make them public this will remind me to explicitly write them out, so I don't get unexpected behaviour. (As default copy constructors will just copy pointer values and as such don't make a "real" second object, which is obviously the goal of a copy :) )
Was This Post Helpful? 0
  • +
  • -

#12 adrainsean  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 01-March 11

Posted 01 March 2011 - 05:42 AM

:)
thanks very well put up .... i had been prying on it for a couple of hours finally got it
thanks :)
Was This Post Helpful? 0
  • +
  • -

#13 diego_pmc  Icon User is offline

  • D.I.C Addict

Reputation: 81
  • View blog
  • Posts: 565
  • Joined: 13-May 09

Posted 27 March 2011 - 01:43 AM

Very easy to follow tutorial, thank you very much! One thing though, if a class is abstract I don't think you need to hide the constructors and asssignment operator; you say you've made the constrcutors protected and/or private as to prevent instances of the abstract classes to be created. In C++ I don't think it's possible to instancize abstract classes anyway, so there no need to hide the contructors.

Edit: Nevermind. It's pure abstract classes that you can't instancize (those with functions such as virtual void func() = 0;). I think Overver and Obervee should have been made pure abstract, but that's only a minor complaint. :)

This post has been edited by diego_pmc: 27 March 2011 - 01:47 AM

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1