我正在实现一个带有通知的观察者设计模式对象,我可以修改以适应各种观察到的类。
下面是观察者框架:
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;
};
所以我想能够传递一个更具体的通知对象(a TimerNotification)每当计时器事件发生,这样我就可以调用一个特定的更新()函数在观察者,所以我做了一个新的观察者类(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";
}
};
当运行时,程序运行接口方法,void update(INotification)而不是更具体的ITimerNotification。问题是,我如何让CTimer类知道TimerObserver而不破坏接口契约,说它只需要一个基本的观察者指针?
回答问题的第一部分:
ITimerNotification* notification = new CTimerNotification(now());
(*it)->update(notification);
此代码将notification
传递给IObserver::update
方法,该方法只有一个:
virtual void update(INotification*)=0;
因此在TestObserver
中调用虚方法。
(*it)->update(notification);
编译器只能对函数名进行静态解析。在这些是虚拟调用的地方,将根据调用方法的对象类型(而不是参数)对实际方法进行运行时绑定。因此,为了通过内置机制进行双重分派,您需要在通知和观察者上同时调用虚拟方法。
参见:
c++中的多重调度
访客模式下的双重分派是如何工作的?
这个主题在Meyer的一本书(我忘了是哪本)中也有详细的介绍