C++ Observer design pattern implementation
I'm using the Observer design pattern in order to manage events in the game I'm currently developping.
I based myself on the implementation demonstrated at http://gameprogrammingpatterns.com/observer.html but improved it in order to ease it's use.
Here it is :
class Observer
{
public:
virtual ~Observer() {}
virtual void onNotify(Subject * entity, Event event) = 0;
private:
};
class Subject
{
public:
Subject() {}
virtual ~Subject() {}
void addObserver(Observer* observer)
{
if (std::find(_observers.begin(), _observers.end(), observer) == _observers.end())
{
_observers.push_back(observer);
}
}
void removeObserver(Observer* observer)
{
std::list<Observer*>::iterator it = std::find(_observers.begin(), _observers.end(), observer);
if (it != _observers.end())
{
*it = NULL;
_eraseQueue.push(it);
}
}
protected:
void notify(Subject * entity, Event event)
{
for (std::list<Observer*>::iterator it = _observers.begin(); it != _observers.end(); ++it)
{
if (*it != NULL)
(*it)->onNotify(entity, event);
}
while (!_eraseQueue.empty())
{
_observers.erase(_eraseQueue.front());
_eraseQueue.pop();
}
}
void notify(Subject * entity, Event event, Observer* observer)
{
if (observer != NULL)
observer->onNotify(entity, event);
}
private:
std::list<Observer*> _observers;
std::queue<std::list<Observer*>::iterator> _eraseQueue;
};
template <typename T>
class EventHandler : public Observer
{
public:
virtual ~EventHandler() {}
virtual void onNotify(Subject * entity, Event event)
{
if (dynamic_cast<T*>(this))
{
auto it = _actions.find(event);
if (it != _actions.end())
{
(dynamic_cast<T*>(this)->*(it->second))(entity);
}
}
}
protected:
template <typename U>
U safe_cast(Subject* entity)
{
if (dynamic_cast<U>(entity))
return (dynamic_cast<U>(entity));
else
throw std::exception("Event thrown on not-matching entity");
}
protected:
std::map<const Event, void (T::*)(Subject *)> _actions;
};
And here's some explanations about what makes it special :
- When removing an element from the observers list of a
Subject
, I'm storing the observers to remove into an erase queue, so that the iterator in thenotify
method still works even when removing an observer inside of thenotify
call. - "Observers" don't inherit from
Observer
directly, but inside they inherit fromEventHandler
wich is a templated class that allows me to automatically call the corresponding pointers to function when receiving an event, without having to manage it in everyObserver
's daugther classes. - The
EventHandler
class implements asafe_cast
method so that I can convert theSubject
received fromonNotify
can be easily and safely casted to their inherited class.
So, maybe you wonder why I'm using a EventHandler
class instead of inheriting directly from the Observer
class, but here's a quick exemple to show you why it's usefull and makes the code much easier to read :
MyClass::MyClass()
{
_actions[GAME_STARTED] = &MyClass::gameStarted;
_actions[CHARACTER_MOVED] = &MyClass::characterMoved;
}
void MyClass::gameStarted(Subject * entity)
{
Game* game = safe_cast<Game*>(entity);
// Do actions on the Game instance
}
void MyClass::characterMoved(Subject * entity)
{
Character* character = safe_cast<Character*>(entity);
// Do actions on the Character instance
}
That's it, my event handling is completly hidden from the final user, he just has to store the events that he wants to listen in his class, and it will automaticaly be handled by the EventHandler
class.
I already now a few ways of improving my implementation of the Observer pattern :
- Using smart pointers,
- Actually, using references instead of pointers,
- Handle the case where the
Subject
instance gets deleted during thenotify
method call.
But I'd like to have your opinion about the other things that I could improve, and your overall feel about this implementation :)
Thanks !
- 313
- 1
- 3
- 11