2012-08-24 47 views
6

我設計應該以這種方式工作的觀察者模式:觀察者稱的EventDispatcherAddEventListener方法,並傳遞一個字符串,它是event的名稱,PointerToItselfPointerToItsMemberMethodC++自己的Observer模式

之後event發生在EventDispatcher內部;它查看訂閱列表,如果有一些,分配給此事件調用observeraction方法。

我來到這EventDispatcher.h小心包含一些僞代碼。

的是兩個問題:

  1. 如何定義的actionstruct 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); 
     }; 
    }; 
}; 
+2

壞你」不要使用增強功能,因爲這樣可以實現一種簡單且類型安全的解決方案,該解決方案將超越您當前的方法並且更加靈活。 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()方法即可。

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

一個行動派生類的一個例子:

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

我可以通過'AddEventListener'指向'observer'的成員函數並從'EventDispatcher'調用它嗎?我該怎麼做?謝謝? – Kolyunya

+0

抱歉,延遲。請避免使用函數指針。在你的DispatchEvent()方法中,你可以只有action-> DoThis(); –

+0

對不起,但我不明白...讓我們說,觀察者有一個非靜態方法'DoSmth()'。如何將此方法傳遞給'EventDispatcher',以及EventDispatcher稍後如何調用此方法? – Kolyunya

1

在其最簡單的形式u_u可以是一個函數指針例如

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

然後你只需提供一個函數,當事件被觸發時被調用。

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

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

您可以定義一個Action類或傳遞一個lambda函數(C++ 11)。在後一種情況下,動作可以被定義爲

function<void (EventDispatcher*)> action; 

,你會如下

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)'作爲函數傳遞給lambda函數。 –

+0

我只是沒有得到你的代碼...它必須是新的標準C++ 11,我還不知道它...謝謝抱歉... – Kolyunya