具有类型信息的观察者模式(C ++)

时间:2013-11-18 20:24:18

标签: c++ templates polymorphism observer-pattern rtti

我正在尝试用c ++实现Observer模式的自定义版本。

这些是我的类(只是界面):

class Observer{
public:
    void observe(std::string behaviour, Observable * observable);
    void stopObserving(std::string behaviour, Observable * observable);
    virtual void notified(std::string behaviour, Observable * observed);
// ...
};

class Observable{
public:
    void notifyBehaviour(std::string behaviour);
    // ...
};

可以像这样使用:

class A : public Observer{
public:
    void notified(std::string behaviour, Observable * observed){
        if (behaviour == "jumping"){
            // ...
        }
    }
};

class B : public Observable{
public:
    void jump(){
        // ...
        notifyBehaviour("jumping");
    }
};

int main(){
    A a;
    B b;
    a.observe("jumping", &b);
    b.jump();
    // ...
}

实现Observer的每个类都可以将自己注册为观察带有行为的Observable。

Observable可以通过“notifyBehaviour”向所有感兴趣的人通知其行为。

每个观察者监听都将通过其“通知”方法通知。

以上工作完美。无论如何在上面的例子中:

void notified(std::string behaviour, Observable * observed){
    if (behaviour == "jumping"){
    // ...
}

我想使用Observable *我传递给通知对象做一些事情。不幸的是,我必须做这样的事情:

void notified(std::string behaviour, Observable * observed){
    if (behaviour == "jumping"){
        auto pointer = dynamic_cast<B *>(observed);
        if (pointer)
            pointer->doSomethingElse();
    }
}

那很难看,可能会产生问题。例如,观察两个不同的跳跃实体将需要多个铸件等待正确的一个。

我的问题是:是否可以传递一些RTTI或调用重载函数或具有正确对象类型的模板?我想要:

class A : public Observer{
public:
    void notified(std::string behaviour, B * observed){
        if (behaviour == "jumping"){
            observed->doSomethingBlike();
            // observed if of type B !
        }
    }
    void notified(std::string behaviour, C * observed){
        if (behaviour == "jumping"){
            observed->doSomethingClike();
            // observed if of type C !
        }
    }
};

所以我只需要实现我想听的各种对象类型。

我尝试过继承,模板,boost :: any但仍然没有运气。

感谢您的想法。

2 个答案:

答案 0 :(得分:0)

在Observed类中声明一个纯虚方法。或者只是一个空的虚函数,所以不需要覆盖。

class Observed {
public:
    virtual ~Observed();
    Observed();
    virtual void DoSomethingElse() {} // OR
    //void DoSomethingElse() = NULL;

    // rest of class

};

答案 1 :(得分:0)

我最近在几个项目中做过这个。基本理念:

我创建了一个基类(Notified),它为您希望接收的每个接口都有一个虚方法:

class Notified
{
public:
   virtual bool Notify(NOTIFIED_EVENT_TYPE_T eventType, uint32 value)
   { return false; };
   virtual bool Notify(NOTIFIED_EVENT_TYPE_T eventType, ITEM_ID_T value)
   { return false; };
   virtual bool Notify(NOTIFIED_EVENT_TYPE_T eventType, const string& value)
   { return false; };
   virtual ~Notified(); 
};

我创建了一个单例,作为一个中心点,用于保存要向其发送消息的内容(从Notified派生)和调用它们的方法:

    class Notifier : public SingletonDynamic<Notifier>
     {

         private:
            ... detail omitted...

         public:

            virtual void Reset();
            virtual bool Init() { Reset(); return true; }
            virtual void Shutdown() { Reset(); }

            void Attach(Notified* observer, NOTIFIED_EVENT_TYPE_T eventType);
            // Detach for a specific event
            void Detach(Notified* observer, NOTIFIED_EVENT_TYPE_T eventType);
            // Detach for ALL events
            void Detach(Notified* observer);

            // This template function (defined in the header file) allows you to
            // add interfaces to Notified easily and call them as needed.  Variants
            // will be generated at compile time by this template.

            template <typename T>
            bool Notify(NOTIFIED_EVENT_TYPE_T eventType, const T& value)
            {
              ...detail omitted
            }



            /* Used for CPPUnit.  Could create a Mock...maybe...but this seems
             * like it will get the job done with minimal fuss.  For now.
             */
            // Return all events that this object is registered for.
            vector<NOTIFIED_EVENT_TYPE_T> GetEvents(Notified* observer);
            // Return all objects registered for this event.
            vector<Notified*> GetNotified(NOTIFIED_EVENT_TYPE_T event);
         };

尝试为Notified类创建模板方法很有吸引力:

template <typename T>
virtual bool Notify(NOTIFIED_EVENT_TYPE_T eventType, const T& value)

但你不能因为它需要是虚拟的,所以你可以让你的派生类来处理它。我想深入挖掘它作为一个模板(元模板的东西),但我认为这会混淆一个通常简单易用和易懂的设计。

这个设计的要点是:
1.通过编译过程直接检查,您可以获得完整的类型安全性调用Notified派生类。 2.如果没有为函数实现处理程序,则可以让Notifier类在返回false时抛出异常。 3.为Notified派生类中的每个处理程序编写代码是微不足道的:

   class MyNotified : public Notified
    {
        virtual bool Notified(NOTIFIED_EVENT_T evt, uint32 value)
        {
          bool result = true;
          switch(evt)
          {
          case EVT_1:
              ...do something...
              break;
          default:
              result = false;
          }
          return result;
        }
   };

我在here找到的帖子中(生活的各个阶段)都有这样的例子。

这有用吗?