6

私はこのように動作するはずのオブザーバー パターンを設計しています: オブザーバーはAddEventListenerメソッドを呼び出しEventDispatcherの名前である文字列を渡しますevent

その後、 ;eventの内部で発生します。EventDispatcherサブスクリプションのリストを調べて、サブスクリプションがある場合は、このイベントに割り当てられた のactionメソッドを呼び出しますobserver

ここまで来ましたEventDispatcher.h注意には、疑似コードが含まれています。

次の 2 つの質問があります。

  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 クラスを定義するか、ラムダ関数 (C++11) を渡すことができます。後者の場合、アクションは次のように定義できます。

function<void (EventDispatcher*)> action;

そして、次のようにオブザーバーを登録します

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

Observer を EventDispatcher に格納するには、おそらくスマートなウィーク ポインターを使用して、登録解除を気にする必要がないようにする必要があります。

編集:次の例を追加しました(可能なサブスクリプションは1つだけですが、アイデアを説明する必要があります-存在しないオブジェクトを参照しないように注意する必要があります)

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

おそらく、「ユーザー」によって派生されるクラスを作成する必要があります。

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

これは、アクション (およびコールバック) を実装する最も安全な方法の 1 つです。

于 2012-08-24T08:07:26.057 に答える
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 に答える