Archived

This topic is now archived and is closed to further replies.

ANSI2000

Implementing observer pattern...

Recommended Posts

Am trying to implement the observer pattern in vc 6.0, but something is wrong
    
subject.h file
#ifndef SUBJECT_H
#define SUBJECT_H

#include <list>

using namespace std;

class Observer;

class Subject
{
public:
	virtual ~Subject();
	
	virtual void attach(Observer pObserver);
	virtual void detach(Observer pObserver);
	virtual void notify();
protected:
	Subject();
private:
	list<Observer> observers;
};
#endif

subject.cpp file
#include "subject.h"

void Subject::attach(Observer pObserver)
{
	observers->push_back(pObserver);
}

void Subject::detach(Observer pObserver)
{
	observers->remove(pObserver);
}

void Subject::notify()
{
	for(list<Observer>::iterator i = observers->begin(); i < observers->end(); i++)
		i->update(this);
}

observer.h file
#ifndef OBSERVER_H
#define OBSERVER_H

class Subject;

class Observer
{
public:
	virtual ~Observer();
	
	virtual void update(Subject pSubject) = 0;
protected:
	Observer();
};

#endif



    
The observer must be able to verify which subject made a change, since it will be observing multiple subjects... Edited by - ANSI2000 on January 30, 2002 4:59:47 PM

Share this post


Link to post
Share on other sites
You pass the subject pointer to the observer, doesn't that tell you who changed?

er, shouldn't it be a list of IObserver*, not Observer? (and update be pure virtual?)


...
misc comments:
#pragma once is a bit easier than messing with all those #ifdef's

Bringing the entire std namespace into the current scope is frowned upon in header files (it forces all users of your class to bring the entire namespace into thier scope as well).

Make a typedef in the class declaration for the list as well.

And, check this out:
    
typedef std::list<Observer*> tyObserverList;
tyObserverList m_Observers;

std::for_each(m_Observers.begin(),
m_Observers.end(),
std::bind1st(std::mem_fun1(Observer::update), this) );


Edited by - Magmai Kai Holmlor on January 30, 2002 8:10:47 PM

Share this post


Link to post
Share on other sites
Update is a pure virtual the Observer Class is abstract


Yes I do pass the pointer of the Subject that should tell me! I was just mentioning, maybe some one else has a better way that's all

Actually the implementation is good am getting erros on the compilation..

Also am I using the right operation to push object on the stack? And to delete object form the stack?

Edited by - ANSI2000 on January 30, 2002 9:15:45 PM

Edited by - ANSI2000 on January 30, 2002 10:03:05 PM

Share this post


Link to post
Share on other sites
Ok here is the new modified code and compiler errors.

observer.h
    
#ifndef OBSERVER_H
#define OBSERVER_H

class Subject;

class Observer
{
public:
virtual ~Observer();

virtual void update(Subject pSubject) = 0;
protected:
Observer();
};

#endif


subject.h

#ifndef SUBJECT_H
#define SUBJECT_H

#include <list>

class Observer;

typedef std::list<Observer*> ObserverList;

class Subject
{
public:
virtual ~Subject();

virtual void attach(Observer *pObserver);
virtual void detach(Observer *pObserver);
virtual void notify();

protected:
Subject();

private:
ObserverList observers;
};

#endif


subject.cpp

#include "subject.h"

void Subject::attach(Observer *pObserver)
{
observers.push_back(pObserver);
}

void Subject::detach(Observer *pObserver)
{
observers.remove(pObserver);
}

void Subject::notify()
{
std::for_each(observers.begin(), observers.end(), std::bind1st(std::mem_fun1(Observer::update), this));
}


The errors...

Deleting intermediate files and output files for project 'Observer - Win32 Debug'.
--------------------Configuration: Observer - Win32 Debug--------------------
Compiling...
main.cpp
subject.cpp
D:\Programming\Projects\CPP\Tests\Observer\subject.cpp(15) : error C2039: 'for_each' : is not a member of 'std'
D:\Programming\Projects\CPP\Tests\Observer\subject.cpp(15) : error C2065: 'for_each' : undeclared identifier
D:\Programming\Projects\CPP\Tests\Observer\subject.cpp(15) : error C2027: use of undefined type 'Observer'
d:\programming\projects\cpp\tests\observer\subject.h(6) : see declaration of 'Observer'
D:\Programming\Projects\CPP\Tests\Observer\subject.cpp(15) : error C2065: 'update' : undeclared identifier
Error executing cl.exe.

Observer.exe - 4 error(s), 0 warning(s)

Well I fixed the problem of update beeing undeclared identifier... By including the observer.h file in the subject.h file, instead of just declaringa prototype of observer like am doing above... Bu the for_each problem still exists...

Edited by - ANSI2000 on January 31, 2002 10:50:06 AM

Share this post


Link to post
Share on other sites
Are you even including <algorithm> for for_each? And subject.cpp needs to #include "observer.h" if it is going to access one of Observer''s functions: this is just basic C/C++ file organisation. The forward declaration only works so long as you''re only manipulating the pointer values.

[ MSVC Fixes | STL | SDL | Game AI | Sockets | C++ Faq Lite | Boost ]

Share this post


Link to post
Share on other sites
no not including <algorithim>

As for Observer I already fixed that problem... Another solution to lists would be a vector then you can use indexing and a regular foor loop...

Edited by - ANSI2000 on February 1, 2002 11:05:13 AM

Share this post


Link to post
Share on other sites
I would use a vector and .reserve(10) on it in the ctor.

To truely remove something from a container you need to call remove and then erase (IIRC) - remove actual puts it at the end of the container.

List may have a member function to erase/remove as the iterator algorithms would be quite slow on a list.

You may need to include "functional" as well.

The list needs to be a list of Observer*

Share this post


Link to post
Share on other sites
Here is the new code, using a Vector instead of a List...

Compiles correctly, I must test it though, havent had the time yet....

observer.h
  
#ifndef OBSERVER_H
#define OBSERVER_H

// Required include files.

#include <vector>

// Application required include files.


/**********************************************************
Observer class

It defines the interface to attach with an object of
the type Subject. It''s has to be subclassed in order
to be applied. It is an abstract interface.
***********************************************************/
class Subject;

class Observer
{
public:
virtual ~Observer();

virtual void update(Subject *pSubject) = 0;
protected:
Observer();
};

/**********************************************************
class Subject

It defines the interface to attach with an object of
the type Observer.

It can attach any number of the Observer type object.
***********************************************************/

typedef std::vector<Observer*> ObserverVector;

class Subject
{
public:
virtual ~Subject();

virtual void attach(Observer *pObserver);
virtual void detach(Observer *pObserver);
virtual void notify();

protected:
Subject();

private:
ObserverVector observers;
};



#endif



observer.cpp
  
// Required include files.


// Application required include files.

#include "observer.h"

void Subject::attach(Observer *pObserver)
{
observers.push_back(pObserver);
}

void Subject::detach(Observer *pObserver)
{
int count = observers.size();

int i;

for (i = 0; i < count; i++)
{
if(observers[i] == pObserver)
break;
}

if(i < count)
observers.erase(observers.begin() + i);
}

void Subject::notify()
{
int count = observers.size();

for (int i = 0; i < count; i++)
(observers[i])->update(this);
}

Share this post


Link to post
Share on other sites