观察者设计模式接口契约设计问题



我正在实现一个带有通知的观察者设计模式对象,我可以修改以适应各种观察到的类。

下面是观察者框架:

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中调用虚方法。

对于第二部分,您需要认识到您希望调用在某种意义上对两个类型是虚拟的,观察者通知。这被称为双调度,需要在c++中做一些工作。 要理解的关键点是函数调用的静态绑定和运行时绑定。在调用点,例如:
(*it)->update(notification);

编译器只能对函数名进行静态解析。在这些是虚拟调用的地方,将根据调用方法的对象类型(而不是参数)对实际方法进行运行时绑定。因此,为了通过内置机制进行双重分派,您需要在通知和观察者上同时调用虚拟方法。

参见:

c++中的多重调度

访客模式下的双重分派是如何工作的?

这个主题在Meyer的一本书(我忘了是哪本)中也有详细的介绍

最新更新