观察者设计模式界面合同设计问题

时间:2011-12-07 04:36:06

标签: c++ inheritance interface

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

这是观察者框架:

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指针?

1 个答案:

答案 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);

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

参见例如:

Multiple dispatch in C++

How does double dispatch work in Visitor pattern?

这个主题也在迈耶的一本书中详细介绍(我忘了哪一本。)