I am busy adding a generic observer mechanism to a legacy C++ application (using Visual Studio 2010, but not using .Net, so .Net delegates are out of the question).
In the design I want to separate the application-specific part as much as possible from the generic observer mechanism.
The most logical way of implementing observers seems this way:
class IDoThisObserver
{
public:
void handlDoThis(int arg1, int arg2) = 0;
};
For every type of observer (IDoThisObserver, IDoThatObserver, ...) the arguments of the methods (handleDoThis, handleDoThat) are different.
What remains in a generic way of storing the observers, like this:
template<typename T>
class ObserverContainer
{
public:
void addObserver (T &t) {m_observers.push_back(&t);}
private:
std::list<T*> m_observers;
};
Calling an observer can't be generalized since the arguments are different for every observer type.
An alternative way would be to 'pack' all arguments into one argument, like this:
struct DoThisInfo
{
DoThisInfo (int arg1, int arg2) : m_arg1(arg1), m_arg2(arg2) {}
int m_arg1;
int m_arg2;
};
And then define a more generic observer, like this:
template<typename T>
class IObserver
{
public:
void notify(const T &t) = 0;
};
And a collection of these observers would then become this:
template<typename T>
class ObserverContainer
{
public:
void addObserver (IObserver<T> &obs) {m_observers.push_back(&obs);}
private:
std::list<IObserver<T>*> m_observers;
};
Now, much more logic can be centrally added to this ObserverContainer, including calling all observers. The 'initiator' of the call only needs to create and fill in the notification structure.
Classes that want to inherit from multiple kinds of observers, need to do it like this:
class MyObserver : public IObserver<NotifyThis>, public IObserver<NotifyThat>
{
...
};
Which of these approaches (observers with multiple explicit arguments or with one struct argument) seems the best? Are there any advantages or disadvantages to either of these approaches?
EDIT: I looked a bit further to alternative approaches, and the Slot/Signal approach seems another good candidate. Are there any important disadvantages in Slot/Signal that I should know of?