2012-08-24 25 views
6

मैं एक पर्यवेक्षक पैटर्न जो इस तरह से काम करना चाहिए डिजाइनिंग हूँ: और पर्यवेक्षक कॉल EventDispatcher की AddEventListener विधि और एक स्ट्रिंग जो event का नाम है गुजरता है, PointerToItself एक PointerToItsMemberMethodसी ++ खुद पर्यवेक्षक पैटर्न

उसके बाद eventEventDispatcher के अंदर होता है; यह सब्सक्रिप्शन की सूची देखता है और यदि कुछ हैं, तो इस घटना को सौंपा गया observer की विधि को कॉल करता है।

मैं इस EventDispatcher.h पर आया हूं। सावधानी में छद्म कोड का थोड़ा सा हिस्सा है।

दो प्रश्न हैं:

  1. मैं struct Subscription में action के प्रकार कैसे परिभाषित करते हैं?
  2. क्या मैं सही तरीके से आगे बढ़ रहा हूं?

पुनश्च: नहीं, मैं नहीं उपयोग करने वाले 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

बुरा करने के लिए आप ' बूस्ट का उपयोग नहीं कर रहे हैं, क्योंकि इससे एक आसान और प्रकार का सुरक्षित समाधान हो सकता है जो आपके वर्तमान दृष्टिकोण को बेहतर प्रदर्शन करेगा और अधिक लचीला होगा। क्या सी ++ 11 समाधानों की अनुमति है? – Ylisar

+0

मुझे अभी तक वास्तव में पता नहीं है, सी ++ 11 क्या है ... यह एक नया मानक है, है ना? मुझे आश्चर्य है, अगर मेरा 'जी ++' पहले से ही जानता है? नया मानक उपयोग करने के लिए ठीक है, यह लाइब्रेरी नहीं है ... – 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

क्या मैं सिर्फ 'एडवेंटर लिस्टनर' को 'पर्यवेक्षक' के सदस्य फ़ंक्शन में एक पॉइंटर पास कर सकता हूं और इसे 'EventDispatcher' से कॉल कर सकता हूं? मैं यह कैसे कर सकता हूं? धन्यवाद? – Kolyunya

+0

देरी के लिए खेद है। फ़ंक्शन पॉइंटर्स का उपयोग करने से बचें। आपकी DispatchEvent() विधि में, आप केवल कार्रवाई कर सकते हैं-> 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

आप या तो एक्शन क्लास को परिभाषित कर सकते हैं या लैम्ब्डा फ़ंक्शन (सी ++ 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); 
    } 
}; 
+0

क्या मैं सिर्फ 'AddEventListener' को पर्यवेक्षक के सदस्य फ़ंक्शन में एक पॉइंटर पास कर सकता हूं और उसे' EventDispatcher 'से कॉल कर सकता हूं? मैं यह कैसे कर सकता हूं? धन्यवाद? – Kolyunya

+0

@ कोल्युन्या बस 'std :: bind (Observer :: whateverMethod, me)' को lambda के बजाय फ़ंक्शन के रूप में पास करें। –

+0

मुझे बस अपना कोड नहीं मिला ... यह नया मानक सी ++ 11 होना चाहिए, मुझे अभी तक यह नहीं पता ... धन्यवाद और क्षमा करें ... – Kolyunya

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^