2012-08-24 15 views
6

私はこのように動作するはずですオブザーバーパターンを設計しています:観察者はC++自身のObserverパターン

EventDispatcherAddEventListenerメソッドを呼び出し、eventの名前である文字列を渡し、PointerToItselfPointerToItsMemberMethodその後、eventEventDispatcherの内部で発生します。サブスクリプションのリストを調べ、ある場合には、このイベントに割り当てられ、のactionメソッドを呼び出します。

私はこれに来ましたEventDispatcher.h注意には擬似コードのビットが含まれています。

ザ・は二つの質問です:私はstruct Subscriptionactionのタイプを定義するにはどうすればよい

  1. 正しい方法で動いていますか?

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

このヘッダはu_uは、例えば、関数ポインタとすることができる最も単純な形式で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); 
     }; 
    }; 
}; 
+2

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

編集しますブーストを使用しないでください。これは、現在のアプローチより優れた柔軟性を備えた簡単で安全なソリューションを可能にするからです。 C++ 11のソリューションは許可されていますか? – Ylisar

+0

私はまだ実際には分かっていませんが、C++ 11は何か...新しい標準ですね。もし私の 'g ++ 'が既にそれを知っていれば、私は疑問に思いますか?新しい標準は使用するのに大丈夫ですが、ライブラリではありません。 – Kolyunya

答えて

1

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

class Action { 
    public: 
     friend class EventDispatcher; 

     virtual SomeResultType DoThis() = 0; 

    private: 
     /* Some common data */ 
}; 

ただ、いくつかの派生からクラス・アクションのaddEventListenerに変数型付け渡します。対応するイベントがトリガされたら、共通データを入力してDoThis()メソッドを呼び出します。

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

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

アクション派生クラスの例:

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

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

+0

'Observer'のメンバ関数へのポインタを' AddEventListener'に渡して 'EventDispatcher'から呼び出すことはできますか?どうしたらいいですか?ありがとうございました? – Kolyunya

+0

遅れて申し訳ありません。関数ポインタの使用は避けてください。 DispatchEvent()メソッドでは、action-> DoThis(); –

+0

申し訳ありませんが、私はそれを取得しません...見てみましょう、オブザーバは非静的メソッド 'DoSmth()'を持っています。このメソッドを 'EventDispatcher'に渡すにはどうしたらいいですか?' EventDispatcher'は後でこのメソッドをどのように呼びますか? – Kolyunya

1

このような実装します

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

次に、イベントがトリガーされるたびに呼び出される関数を提供するだけです。

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

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

アクションクラスを定義するか、ラムダ関数(C++ 11)を渡すことができます。後者の場合、アクションは

function<void (EventDispatcher*)> action; 

として定義することができ、

あなたはおそらく、そのようなあなたのこと、のEventDispatcherにオブザーバーを保存するために、スマート弱いポインタを使用する必要があり
Observer * me = this; 
observable->AddEventListener (this, "EventName", [me] (EventDispatcher* dispatcher) { 
    // code here; me is available 
}); 

を次のようにオブザーバを登録します登録を気にする必要はありません。悪いへ

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); 
    } 
}; 
+0

オブザーバのメンバ関数へのポインタを 'AddEventListener'に渡して' EventDispatcher'から呼び出すことはできますか?どうしたらいいですか?ありがとうございました? – Kolyunya

+0

@Kolyunyaはラムダの代わりに 'std :: bind(Observer :: whateverMethod、me)'を関数として渡すだけです。 –

+0

私はちょうどあなたのコードを取得しないでください...それは新しい標準C++ 11でなければなりません、私はまだそれを知らない...おかげで申し訳ありません... – Kolyunya

関連する問題