C ++自己的观察者模式

时间:2012-08-24 07:55:16

标签: c++ pointers function-pointers observer-pattern observers

我正在设计一个观察者模式,它应该以这种方式工作:观察者调用AddEventListener的{​​{1}}方法并传递一个字符串,该字符串是EventDispatcher的名称, PointerToItself PointerToItsMemberMethod

event内发生event之后;它会查看订阅列表,如果有一些订阅,则分配给此事件会调用EventDispatcher的{​​{1}}方法。

我来到这个action注意包含一些伪代码。

这是两个问题:

  1. 如何在observer
  2. 中定义EventDispatcher.h的类型
  3. 我是否正确行事?
  4. PS :不,我不会使用action任何其他库。

    struct Subscription

    此标头在boost

    中实现如下
    #pragma once
    
    #include <vector>
    #include <string>
    
    using namespace std;
    
    struct Subscription
    {
            void*                   observer;
            string                  event;
            /*  u_u  */             action;
    };
    
    class EventDispatcher
    {
        private:
            vector<Subscription>    subscriptions;
    
        protected:
            void                    DispatchEvent ( string event );
    
        public:
            void                    AddEventListener ( Observer* observer , string event , /*  u_u  */ action );
            void                    RemoveEventListener ( Observer* observer , string event , /*  u_u  */ action );
    };
    

3 个答案:

答案 0 :(得分:3)

您可以定义Action类或传递lambda函数(C ++ 11)。在后一种情况下,行动可以定义为

function<void (EventDispatcher*)> action;

您将按如下方式注册观察者

Observer * me = this;
observable->AddEventListener (this, "EventName", [me] (EventDispatcher* dispatcher) {
   // code here; me is available
});

您应该使用智能弱指针将Observers存储在EventDispatcher中,这样您就不必关心取消注册了。

编辑:添加了以下示例(可能只有一个订阅,但应说明这个想法 - 您必须小心不要引用不再存在的对象)

struct Observable {
   std::weak_ptr<function<void (const Observable&)>> action;

   void AddEventListener (std::weak_ptr<function<void (const Observable&)>> theAction) {
      action = theAction;
   }

   void EventRaised () {
      if (!action.expired ()) {
         auto theAction = action.lock ();
         (*theAction) (*this);
      }
   }
};

struct Observer {
...
   void CallOnEvent (const Observable & observable) {
      // do something
   }

   // field to store the action as long as it is needed
   std::shared_ptr<function<void (const Observable&)>> action;

   void ... {
      auto me = this;
      action = std::make_shared<function<void (const Observable&)>> (
         [me] (const Observable& observable) {
             me->CallOnEvent (observable);
         }
      );
      // we could have as well used std::bind
      observable.AddEventListener (action);
   }
};

答案 1 :(得分:1)

在最简单的形式中,u_u可以是一个函数指针,例如

typedef void (*u_u)(void*); // or whatever arguments u like

然后你只提供一个在触发事件时调用的函数。

void myaction(void* arg)
{
  ...
}

Subscription s;
...
s.action = myaction;

答案 2 :(得分:1)

也许您应该创建一个由“用户”派生的类:

class Action {
   public:
      friend class EventDispatcher;

      virtual SomeResultType DoThis() = 0;

   private:
      /* Some common data */
};

只需将一些派生类的Action类型变量传递给AddEventListener。触发相应的事件时,只需填写公共数据并调用DoThis()方法。

void EventDispatcher::DispatchEvent ( string event )
{
    int key = 0;
    while ( key < this->subscriptions.size() )
    {
        Subscription subscription = this->subscriptions[key];
        if ( subscription.event == event )
        {
            subscription->action();
        };
    };
};

对于AddEventListener:

void EventDispatcher::AddEventListener ( Observer* observer , string event , Action* action )
{
    Subscription subscription = { observer , event , action );
    this->subscriptions.push_back ( subscription );
};

Action派生类的一个示例:

class myAction: public Action {
   public:
      // Implement the DoThis() method
      void SomeResultType DoThis() {
          cout << "Hello World!";
          return SomeValue;
      }
};

// To use the action,
myAction* act = new myAction;
myEventDispatcher.AddEventListener(someObserver, "HelloWorld", act);

这是实施操作(和回调)的最安全的方法之一。