2013-09-01 9 views
5

मैं एक सी ++ आवेदन में घटनाओं को लागू करने के लिए विभिन्न दृष्टिकोणों पर विचार कर रहा हूं। एक अधिसूचना केंद्र के माध्यम से एक केंद्रीकृत घटना प्रेषण को लागू करने के लिए एक सुझाव है। कार्यक्रमों के स्रोतों और लक्ष्यों के लिए एक विकल्प सीधे संवाद करने के लिए होगा। हालांकि, मुझे अधिसूचना केंद्र दृष्टिकोण के बारे में आरक्षण है। जैसा कि मैंने उन्हें देखा है, मैं दोनों दृष्टिकोणों की रूपरेखा तैयार करूंगा (मैं उनके बारे में कुछ गलत समझ सकता हूं, मैंने पहले कभी ईवेंट हैंडलिंग लागू नहीं किया है)।एक केंद्रीकृत घटना प्रेषण के पेशेवरों और विपक्ष

ए) प्रत्यक्ष संचार। घटनाक्रम उनके स्रोत के इंटरफेस का हिस्सा हैं। , मैं क्या समझ से

struct Source 
{ 
    Event</*some_args_here*/> InterestingEventA; 
    Event</*some_other_args_here*/> InterestingEventB; 
}; 

class Target 
{ 
public: 
    void Subscribe(Source& s) 
    { 
     s.InterestingEventA += CreateDelegate(&MyHandlerFunction, this); 
    } 

private: 
    void MyHandlerFunction(/*args*/) { /*whatever*/ } 
}; 

(को बढ़ावा देने :: संकेतों, क्यूटी संकेत/स्लॉट और: घटना में रुचि रखने वाले वस्तुओं किसी भी तरह स्रोत वर्ग का एक उदाहरण पर भी नियंत्रण प्राप्त है और इसकी घटना (रों) की सदस्यता चाहिए। नेट घटनाएं इस तरह काम करती हैं, लेकिन मैं गलत हो सकता हूं।)

बी) अधिसूचना केंद्र। घटनाएं उनके स्रोत के इंटरफ़ेस में दिखाई नहीं दे रही हैं। सभी घटनाएं कुछ अधिसूचना केंद्र पर जाती हैं, जो शायद एक सिंगलटन के रूप में लागू होती हैं (इससे बचने पर किसी भी सलाह की सराहना की जाएगी), क्योंकि उन्हें निकाल दिया जाता है। लक्षित वस्तुओं को स्रोतों के बारे में कुछ भी नहीं पता है; वे अधिसूचना केंद्र तक पहुंचकर कुछ घटना प्रकारों की सदस्यता लेते हैं। एक बार अधिसूचना केंद्र को एक नया कार्यक्रम प्राप्त हो जाने पर, यह उस विशेष घटना में रुचि रखने वाले सभी ग्राहकों को सूचित करता है।

class NotificationCenter 
{ 
public: 
    NotificationCenter& Instance(); 

    void Subscribe(IEvent& event, IEventTarget& target); 
    void Unsubscribe(IEvent& event, IEventTarget& target); 

    void FireEvent(IEvent& event); 
}; 

class Source 
{ 
    void SomePrivateFunc() 
    { 
     // ... 
     InterestingEventA event(/* some args here*/); 
     NotificationCenter::Instance().FireEvent(event); 
     // ... 
    } 
}; 

class Target : public IEventTarget 
{ 
public: 
    Target() 
    { 
     NotificationCenter::Instance().Subscribe(InterestingEventA(), *this); 
    } 

    void OnEvent(IEvent& event) override {/**/} 
}; 

(मैं पोको, जो, जहाँ तक मैं समझता हूँ, दोनों दृष्टिकोण को लागू करता है से शब्द "अधिसूचना केंद्र" लिया)।

मैं इस दृष्टिकोण के लिए कुछ पेशेवर देख सकता हूं; लक्ष्य के लिए अपनी सदस्यता बनाने के लिए यह आसान होगा क्योंकि उन्हें स्रोतों तक पहुंच की आवश्यकता नहीं होगी। इसके अलावा, जीवन भर में प्रबंधन की कोई समस्या नहीं होगी: स्रोतों के विपरीत, अधिसूचना केंद्र हमेशा लक्ष्यों को पार कर जाएगा, इसलिए वे हमेशा अपने विनाशकों में सदस्यता छोड़ने का लक्ष्य रखते हैं, इस पर चिंता किए बिना कि स्रोत अभी भी मौजूद है (यह एक प्रमुख बात है जिसे मैं प्रत्यक्ष रूप से देख सकता हूं संचार)। हालांकि, मुझे डर है कि इस दृष्टिकोण unmaintainable कोड को जन्म दे सकता हूँ, क्योंकि:

  1. घटनाओं के सभी प्रकार, शायद पूरी तरह से एक दूसरे से संबंधित नहीं है, यह एक बड़ा सिंक करने के लिए जाना होगा।

  2. अधिसूचना केंद्र को लागू करने का सबसे स्पष्ट तरीका एक सिंगलटन के रूप में है, इसलिए यह ट्रैक करना मुश्किल होगा कि ग्राहकों की सूची में कौन और कब संशोधित होता है।

  3. घटनाक्रम किसी भी इंटरफ़ेस में दिखाई नहीं दे रहे हैं, इसलिए यह देखने का कोई तरीका नहीं है कि कोई विशेष ईवेंट किसी भी स्रोत से संबंधित है या नहीं।

इन विपक्ष का एक परिणाम के रूप में, मुझे डर है कि के रूप में आवेदन बढ़ता है यह वस्तुओं के बीच कनेक्शन को ट्रैक करना बहुत मुश्किल हो जाएगा (मैं क्यों कुछ विशेष घटना आग नहीं है समझने की कोशिश कर समस्याओं की कल्पना कर रहा हूँ कर रहा हूँ , उदाहरण के लिए)।

मैं "अधिसूचना केंद्र" दृष्टिकोण के पेशेवरों और विपक्ष के बारे में सलाह ढूंढ रहा हूं। क्या यह बरकरार है? क्या यह हर तरह के अनुप्रयोगों में फिट है? शायद कार्यान्वयन में सुधार करने के तरीके हैं? मैंने वर्णित दो दृष्टिकोणों के साथ तुलना, साथ ही साथ किसी अन्य घटना प्रबंधन सुझावों का भी स्वागत है।

+0

आपको कुछ डिज़ाइन जानकारी देना चाहिए, आपकी प्रदर्शन बाधाएं, कनेक्शन की संख्या और मल्टीथ्रेडिंग विशेष रूप से क्या होनी चाहिए। आम तौर पर केंद्रीकृत दृष्टिकोण प्रबंधक के लिए आसान है जो मुझे लगता है। – dzada

+0

@dzada, कोई multithreading नहीं। कनेक्शन की संख्या अभी लगभग सौ है, लेकिन मुझे लगता है कि अगर सब्सक्रिप्शन बनाना संभव हो जाए तो यह तेजी से बढ़ेगा, शायद 2 या 3 सौ। आवेदन एक छोटा सा खेल है, इसलिए प्रदर्शन महत्वपूर्ण है; हालांकि, अभी तक, घटनाएं गंभीर प्रदर्शन चिंताओं के कारण अक्सर ट्रिगर नहीं होती हैं। – user2478832

+0

यहां एक समान प्रश्न है। http://programmers.stackexchange.com/questions/22528/does-notification-center-pattern-encourage-good-or-bad-program- डिज़ाइन – ZijingWu

उत्तर

4

ये दृष्टिकोण ऑर्थोगोनल हैं। जब विशिष्ट वस्तुओं के बीच घटनाओं का आदान-प्रदान किया जाता है तो प्रत्यक्ष संचार का उपयोग किया जाना चाहिए। अधिसूचना केंद्र दृष्टिकोण केवल प्रसारण कार्यक्रमों के लिए उपयोग किया जाना चाहिए, उदा।जब आप किसी दिए गए प्रकार की सभी घटनाओं को उनके स्रोत के बावजूद संसाधित करना चाहते हैं, या जब आप किसी ऑब्जेक्ट को कुछ ईवेंट में भेजना चाहते हैं जिसे आप पहले से नहीं जानते हैं।

सिंगलेट से बचने के लिए, सीधे संचार के लिए कोड का पुन: उपयोग करें और अधिसूचना केंद्र ऑब्जेक्ट को उन सभी घटनाओं की सदस्यता लें जिन्हें आप इस तरह से संसाधित करना चाहते हैं। चीजों को व्यवस्थित रखने के लिए, आप इसे उत्सर्जित वस्तुओं में करेंगे।

प्रत्यक्ष संचार के साथ जीवन भर से संबंधित समस्याएं आमतौर पर किसी भी घटना के लिए सदस्यता लेने वाली प्रत्येक कक्षा को एक विशिष्ट आधार वर्ग से प्राप्त की जानी चाहिए; Boost.Signals में, इस वर्ग को trackable कहा जाता है। आपके CreateDelegate फ़ंक्शन के समतुल्य trackable के भीतर डेटा सदस्य में दिए गए ऑब्जेक्ट के लिए सदस्यता के बारे में जानकारी संग्रहीत करता है। trackable के विनाश पर, मिलान Unsubscribe फ़ंक्शंस को कॉल करके सभी सदस्यता रद्द कर दी गई हैं। ध्यान दें कि यह थ्रेड-सुरक्षित नहीं है, क्योंकि trackable के विनाशक को व्युत्पन्न वर्ग विनाशक खत्म होने के बाद ही बुलाया जाता है - ऐसी अवधि होती है जहां आंशिक रूप से नष्ट ऑब्जेक्ट अभी भी ईवेंट प्राप्त कर सकता है।

+0

"ऑर्थोगोनल" कंप्यूटर प्रोग्रामिंग में एक बहुत गलत समझा शब्द है। स्पष्ट होने के लिए आप कह सकते हैं कि दो दृष्टिकोण पूरी तरह से अलग और पारस्परिक रूप से स्वतंत्र हैं। दूसरे शब्दों में, दो अलग-अलग स्वतंत्र प्रणालियों, भले ही आपके पास एक ही कम्प्यूटेशनल वातावरण में दोनों सिस्टम हों। –

1

हमें अधिसूचना केंद्र डिजाइन सीमित करना चाहिए, इसमें कोड बनाए रखने के लिए बहुत सारे विपक्ष हैं।

  1. यह कर सकते हैं फोन करने वाले कोड, जो वास्तव में स्पष्ट बाँध पर्यवेक्षक और लक्षित करेंगे प्रत्यक्ष संचार में वस्तु से सुराग प्राप्त कार्यान्वयन में वस्तु संबंध जहाज छिपा हुआ, तुम नहीं।
  2. आप हेडर से भी इंटरफ़ेस नहीं देख सकते हैं, आपको को कार्यान्वयन में देखना होगा।
  3. आपने अधिसूचना केंद्र के साथ अपने व्यापार को तार्किक बांध दिया है, आप आसानी से व्यापार घटक का परीक्षण नहीं कर सकते हैं और इसे अन्य परियोजना में पुन: उपयोग नहीं कर सकते हैं।

NotificationCenter के लाभ है कि आप घटना स्रोत पता करने की जरूरत नहीं है, इसलिए आप केवल NotificationCenter का उपयोग करना चाहिए जब वहाँ एक ही घटना, या यहाँ तक स्रोत नंबर बदल जाएगा के लिए कई घटना स्रोत है।

उदाहरण के लिए, विंडोज प्लेटफार्म में आप सभी विंडोज़ आकार बदलना चाहते हैं, लेकिन साथ ही नई विंडो बनाई जा सकती है।

+0

वास्तव में आप अधिसूचना केंद्र के माध्यम से घटनाओं को भेजकर और प्राप्त करके "व्यापार घटक" इकाई-परीक्षण कर सकते हैं। मुझे नहीं लगता कि यह इतना कठिन है ... –

+0

थ्रेड सुरक्षित कार्यक्षमता प्रदान करने के लिए अन्य कक्षा पर अधिसूचना केंद्र निर्भरता के बारे में सोचें, तो यह इतना आसान नहीं हो सकता है। मेरा मतलब यह नहीं है कि यह हमेशा कठिन होता है, लेकिन किसी भी अनावश्यक निर्भरता इकाई-परीक्षण को यथार्थवादी में बहुत कठिन बना सकती है। – ZijingWu

+0

प्रश्न का मेरा उत्तर देखें: ईवेंट संचालित आर्किटेक्चर के साथ आप अक्सर मल्टीथ्रेडिंग से बच सकते हैं। –

2

मैं के रूप में प्रश्न के लिए आवश्यक है (हालांकि मैं इसे DataBus, Dispatcher या Publisher/Subscriber फोन चाहते हैं, बजाय) पेशेवरों और "NotificationCenter" समाधान के विपक्ष पर ध्यान दिया जाएगा।

पेशेवरों:

  • वर्गों की उच्च decoupling
  • एक घटना का सब्सक्राइबर घटना
  • कन्करेंसी प्रबंधन सरल है का स्रोत पता करने के लिए यदि आप एक अतुल्यकालिक का उपयोग की जरूरत नहीं है NotificationCenter (आप cpu समय के शेड्यूलर के रूप में NotificationCenter का उपयोग करके मल्टीथ्रेडिंग से बच सकते हैं)।
  • एक घटना चालित वास्तुकला higly परीक्षण योग्य है/नमूदार

विपक्ष:

  • इंटरफ़ेस निहित है (अर्थातएक वर्ग के इंटरफेस की घटनाओं का खुलासा नहीं करता)
  • आवेदन के विभाजन के लिए महत्वपूर्ण है, ताकि कक्षाएं किसी अन्य अनुप्रयोग में
  • Reusability कठिन हो जाता है में राज्य के दोहराव से बचने के (जब आप एक वर्ग का पुन: उपयोग करना चाहते हैं किसी अन्य अनुप्रयोग में, यह अपने आप के साथ लाता है NotificationCenter)
  • यह उत्पादन के लिए इनपुट से घटनाओं के प्रवाह में एक नया विस्तार सम्मिलित करने के लिए मुश्किल है (यानी: वर्ग AE की सूचनाओं के लिए उत्सर्जन करता है, तो घटना E और वर्ग B रजिस्टर, आप नहीं कर सकतेकी सामग्री बदलने के लिए "0" A और B के बीच एक कक्षा डालेंचलिए इस पर कुछ प्रकार का विस्तार करने के लिए कहते हैं)
  • NotificationCenter क्लाइंट की त्रुटियों का प्रबंधन करना चाहिए (यानी। NotificationCenter को ईवेंट हैंडलर में फेंकने वाले निष्कर्षों को पकड़ने के लिए अपवाद हैंडलर प्रदान करना चाहिए)।

इसके अलावा, मैं यह इंगित करना चाहता हूं कि यह अधिसूचना नहीं है कि अधिसूचना केंद्र एक सिंगलटन हो। असल में आपके पास अधिसूचना केंद्र के कई उदाहरण हो सकते हैं, प्रत्येक प्रबंधन की विभिन्न श्रेणियों का प्रबंधन करता है (उदाहरण के लिए एक एम्बेडेड सिस्टम में आप निम्न स्तर के हार्डवेयर ईवेंट के लिए अधिसूचना केंद्र प्राप्त कर सकते हैं और दूसरा उच्च स्तरीय तर्क के लिए)।

+0

"Concurrency प्रबंधन को सरल बनाया गया है", वास्तव में मुझे ऐसा नहीं लगता है। जो कुछ भी आप घटक और कॉलर बहु-थ्रेड या केवल एकल धागा है, अधिसूचना केंद्र को थ्रेड सुरक्षित होना चाहिए (क्योंकि इसे अन्य घटक घटनाओं को संभालने की आवश्यकता है), जिसके लिए अधिसूचना केंद्र लागू करने की आवश्यकता है सावधानी बरतनी चाहिए, इसे लॉक को जल्दी से रिलीज़ करने की आवश्यकता है जितना संभव हो, धीमी घटना हैंडलर को आमंत्रित करते समय अधिसूचना केंद्र लॉक पकड़ सकता है और आपके घटक को आग घटना में अवरुद्ध कर सकता है। – ZijingWu

+0

@ZijingWu कई मामलों में आप अधिसूचना केंद्र के रूप में अधिसूचना के रूप में मल्टीथ्रेड से बच सकते हैं। जब आप किसी ईवेंट-संचालित आर्किटेक्चर का चयन करते हैं तो यह सबसे अच्छा समाधान है। –

+0

क्या आप एक उदाहरण प्रदान कर सकते हैं कि इसे शेड्यूलर के रूप में कैसे उपयोग किया जा सकता है। मैं वास्तव में समझ में नहीं आता कि इसका उपयोग बहु-थ्रेड से बचने के लिए कैसे किया जा सकता है। – ZijingWu

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