Я занят добавлением универсального механизма наблюдателя в устаревшее приложение C ++ (использующее Visual Studio 2010, но не использующее .Net, поэтому о делегатах .Net не может быть и речи).
В дизайне я хочу как можно больше отделить специфичную для приложения часть от общего механизма наблюдателя.
Наиболее логичный способ реализации наблюдателей выглядит так:
class IDoThisObserver
{
public:
void handlDoThis(int arg1, int arg2) = 0;
};
Для каждого типа наблюдателя (IDoThisObserver, IDoThatObserver, ...) аргументы методов (handleDoThis, handleDoThat) разные.
Что остается в общем способе хранения наблюдателей, например:
template<typename T>
class ObserverContainer
{
public:
void addObserver (T &t) {m_observers.push_back(&t);}
private:
std::list<T*> m_observers;
};
Вызов наблюдателя нельзя обобщить, поскольку аргументы различны для каждого типа наблюдателя.
Альтернативный способ - «упаковать» все аргументы в один аргумент, например:
struct DoThisInfo
{
DoThisInfo (int arg1, int arg2) : m_arg1(arg1), m_arg2(arg2) {}
int m_arg1;
int m_arg2;
};
А затем определите более общего наблюдателя, например:
template<typename T>
class IObserver
{
public:
void notify(const T &t) = 0;
};
И тогда набор этих наблюдателей стал бы таким:
template<typename T>
class ObserverContainer
{
public:
void addObserver (IObserver<T> &obs) {m_observers.push_back(&obs);}
private:
std::list<IObserver<T>*> m_observers;
};
Теперь к этому ObserverContainer можно централизованно добавить гораздо больше логики, включая вызов всех наблюдателей. «Инициатору» звонка нужно только создать и заполнить структуру уведомления.
Классы, которые хотят наследовать от нескольких типов наблюдателей, должны делать это следующим образом:
class MyObserver : public IObserver<NotifyThis>, public IObserver<NotifyThat>
{
...
};
Какой из этих подходов (наблюдатели с несколькими явными аргументами или с одним аргументом структуры) кажется лучшим? Есть ли преимущества или недостатки у любого из этих подходов?
РЕДАКТИРОВАТЬ: я немного изучил альтернативные подходы, и подход слот / сигнал кажется еще одним хорошим кандидатом. Есть ли какие-либо важные недостатки в Slot / Signal, о которых мне следует знать?