我正在努力实现一个带有通知的观察者设计模式 我可以改变以适应各种观察类的对象。
这是观察者框架:
notify.h:
class INotification //Notification container
{
public:
virtual ~INotification()=0;
};
inline INotification::~INotification() {}
class IObserver
{
public:
virtual ~IObserver();
virtual void update(INotification*)=0;
};
inline IObserver::~IObserver() {}
class ISubject
{
public:
virtual ~ISubject();
virtual void attach(IObserver*)=0;
virtual void detach(IObserver*)=0;
virtual void notify()=0; //Note: observer deletes notifications
};
inline ISubject::~ISubject() {}
我正在实现一个计时器类,我希望其他类可以观察计时器事件:
timer.h:
class ITimerObserver;
class ITimer : public ISubject
{
public:
virtual ~ITimer();
virtual void setInterval(const unsigned int,const unsigned int)=0; //Seconds, Microseconds
virtual void run()=0; //Check for triggering
virtual const timeval& now()=0;
virtual bool isItTime(const timeval&,const timeval&)=0;
};
inline ITimer::~ITimer() {}
class CTimer : public ITimer
{
protected:
std::vector<IObserver*> observers;
timeval interval; //How often we are triggering
timeval lastTrigger; //When we were last triggered
timeval current; //Our current time
private:
virtual ~CTimer();
virtual void attach(IObserver*);
virtual void detach(IObserver*);
virtual void notify();
virtual void setInterval(const unsigned int,const unsigned int); //Seconds, Microseconds
virtual void run(); //Check for triggering
virtual const timeval& now();
virtual bool isItTime(const timeval&,const timeval&);
};
class ITimerNotification : public INotification
{
public:
virtual ~ITimerNotification();
virtual const timeval& getTime()=0;
};
inline ITimerNotification::~ITimerNotification() {}
class CTimerNotification : public ITimerNotification
{
public:
CTimerNotification(const timeval& t)
{
time = t;
}
protected:
timeval time;
private:
virtual ~CTimerNotification();
virtual const timeval& getTime()
{
return time;
}
};
class ITimerObserver : public IObserver
{
public:
virtual void update(ITimerNotification*)=0;
};
所以我希望每当发生一个计时器事件时能够传递一个更具体的Notification对象(一个TimerNotification),这样我就可以在观察者上调用一个特定的update()函数,所以我创建了一个新的Observer类(ITimerObserver) )。
这是一个通知观察者计时器事件的函数:
void CTimer::notify()
{
std::vector<IObserver*>::iterator it;
for(it=observers.begin();it!=observers.end();++it)
{
ITimerNotification* notification = new CTimerNotification(now());
(*it)->update(notification);
}
}
这是实际的观察者本身:
class TestObserver : public ITimerObserver
{
public:
virtual void update(INotification* note)
{
std::cout<<"???: TestObserver: update()!\n";
}
virtual void update(ITimerNotification* note)
{
std::cout<< note->getTime().tv_sec << "." << note->getTime().tv_usec <<": TestObserver: update()!\n";
}
};
运行时,程序运行接口方法,无效更新(INotification),而不是我期望的更具体的ITimerNotification。麻烦的是,如何让CTimer类了解TimerObserver而不破坏接口契约,即只需要一个Base Observer指针?
答案 0 :(得分:1)
回答问题的第一部分:
ITimerNotification* notification = new CTimerNotification(now());
(*it)->update(notification);
此代码将notification
传递给IObserver::update
方法,其中只有一个方法:
virtual void update(INotification*)=0;
因此在TestObserver
中调用该虚拟方法。
对于第二部分,您需要认识到您希望某个意义上的呼叫在两个类型上是虚拟的, observer 和通知。这称为 double dispatch ,需要在C ++中进行一些工作。
要理解的关键是函数调用的静态和运行时绑定。在呼叫点,例如:
(*it)->update(notification);
编译器只能对函数名称进行静态解析。在这些是虚拟调用的情况下,将根据调用该方法的对象类型(而不是参数)对实际方法进行运行时绑定。因此,为了通过内置机制进行双重调度,您需要在通知和观察者上调用虚方法。
参见例如:
How does double dispatch work in Visitor pattern?
这个主题也在迈耶的一本书中详细介绍(我忘了哪一本。)