6

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

之后event发生在EventDispatcher; 它查看订阅列表,如果有的话,分配给这个事件的action方法调用observer.

我来到了这个EventDispatcher.hCAUTION包含一些伪代码。

有两个问题:

  1. 如何定义actionin的类型struct Subscription
  2. 我走对了吗?

PS:不,我不会使用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 );
};

这个头文件是这样实现的EventDispatcher.cpp

#include "EventDispatcher.h"

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

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

void    EventDispatcher::RemoveEventListener ( Observer* observer , string event , /* */ action )
{
    int key = 0;
    while ( key < this->subscriptions.size() )
    {
        Subscription subscription = this->subscriptions[key];
        if ( subscription.observer == observer && subscription.event == event && subscription.action == action )
        {
            this->subscriptions.erase ( this->subscriptions.begin() + key );
        };
    };
};
4

3 回答 3

3

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

function<void (EventDispatcher*)> action;

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

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

您可能应该使用智能弱指针将观察者存储在 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);
   }
};
于 2012-08-24T08:08:53.193 回答
1

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

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

那么您只需提供一个在触发事件时调用的函数。

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

Subscription s;
...
s.action = myaction;
于 2012-08-24T08:01:34.077 回答
1

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

class Action {
   public:
      friend class EventDispatcher;

      virtual SomeResultType DoThis() = 0;

   private:
      /* Some common data */
};

只需将一些派生自类动作类型的变量传递给 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);

这是实现动作(和回调)的最安全方式之一。

于 2012-08-24T08:07:26.057 回答