डबल डिस्पैच: Difference between revisions

From Vigyanwiki
(Created page with "{{Polymorphism}} सॉफ्टवेयर इंजीनियरिंग में, डबल डिस्पैच एकाधिक प्रेषण क...")
 
No edit summary
 
(12 intermediate revisions by 4 users not shown)
Line 1: Line 1:
{{Polymorphism}}
{{Polymorphism}}
[[सॉफ्टवेयर इंजीनियरिंग]] में, डबल डिस्पैच [[ एकाधिक प्रेषण ]] का एक विशेष रूप है, और एक तंत्र है जो कॉल में शामिल दो ऑब्जेक्ट के रनटाइम प्रकार के आधार पर फ़ंक्शन कॉल को विभिन्न ठोस कार्यों में भेजता है। अधिकांश [[ वस्तु के उन्मुख ]] सिस्टम में, कोड में फ़ंक्शन कॉल से कॉल किया जाने वाला ठोस फ़ंक्शन एकल ऑब्जेक्ट के गतिशील प्रकार पर निर्भर करता है और इसलिए उन्हें [[ एकल प्रेषण ]] कॉल या बस [[आभासी कार्य]] कॉल के रूप में जाना जाता है।
[[सॉफ्टवेयर इंजीनियरिंग]] में, '''डबल डिस्पैच''' [[ एकाधिक प्रेषण |मल्टीप्ल डिस्पैच]] का विशेष रूप है, और सिस्टम है जो कॉल में सम्मिलित दो ऑब्जेक्ट के रनटाइम टाइप के आधार पर फंक्शन कॉल को विभिन्न कठिन कार्यों में भेजता है। अधिकांश [[ वस्तु के उन्मुख |वस्तु के उन्मुख]] प्रणाली में, कोड में फंक्शन कॉल से कॉल किया जाने वाला कठिन फंक्शन एकल ऑब्जेक्ट के गतिशील टाइप पर निर्भर करता है और इसलिए उन्हें [[ एकल प्रेषण |एकल डिस्पैच]] कॉल या बस [[आभासी कार्य]] कॉल के रूप में जाना जाता है।


[[डैन इंगल्स]] ने सबसे पहले स्मॉलटॉक में डबल डिस्पैचिंग का उपयोग करने का तरीका बताया, इसे [[एकाधिक बहुरूपता]] कहा।<ref>A Simple Technique for Handling Multiple Polymorphism. In Proceedings of [[OOPSLA]] '86, Object–Oriented Programming Systems, Languages and Applications, pages 347–349, November 1986. Printed as SIGPLAN Notices, 21(11). {{ISBN|0-89791-204-7}}</ref>
[[डैन इंगल्स]] ने सबसे पहले स्मॉलटॉक में डबल डिस्पैचिंग का उपयोग करने का विधि बताया था, इसे [[एकाधिक बहुरूपता|मल्टीप्ल बहुरूपता]] कहा गया था।<ref>A Simple Technique for Handling Multiple Polymorphism. In Proceedings of [[OOPSLA]] '86, Object–Oriented Programming Systems, Languages and Applications, pages 347–349, November 1986. Printed as SIGPLAN Notices, 21(11). {{ISBN|0-89791-204-7}}</ref>




==अवलोकन==
==अवलोकन==
सामान्य समस्या यह है कि किसी संदेश को न केवल प्राप्तकर्ता पर बल्कि तर्कों पर भी निर्भर करते हुए विभिन्न तरीकों से कैसे भेजा जाए।
सामान्य समस्या यह है कि किसी मैसेज को न केवल प्राप्तकर्ता पर किन्तु तर्कों पर भी निर्भर करते हुए विभिन्न विधियों से कैसे भेजा जाए।


उस अंत तक, सीएलओएस जैसी प्रणालियाँ एकाधिक प्रेषण लागू करती हैं। डबल डिस्पैच एक और समाधान है जो धीरे-धीरे उन प्रणालियों पर बहुरूपता को कम करता है जो मल्टीपल डिस्पैच का समर्थन नहीं करते हैं।
उस अंत तक, सीएलओएस जैसी प्रणालियाँ मल्टीप्ल डिस्पैच प्रयुक्त करती हैं। डबल डिस्पैच एक और समाधान है जो धीरे-धीरे उन प्रणालियों पर बहुरूपता को कम करता है जो मल्टीपल डिस्पैच का समर्थन नहीं करते हैं।


==मामलों का प्रयोग करें==
==स्थितियों का प्रयोग करें==
डबल डिस्पैच उन स्थितियों में उपयोगी है जहां गणना का विकल्प उसके तर्कों के रनटाइम प्रकारों पर निर्भर करता है। उदाहरण के लिए, एक प्रोग्रामर निम्नलिखित स्थितियों में डबल डिस्पैच का उपयोग कर सकता है:
डबल डिस्पैच उन स्थितियों में उपयोगी है जहां गणना का विकल्प उसके तर्कों के रनटाइम टाइपों पर निर्भर करता है। उदाहरण के लिए प्रोग्रामर निम्नलिखित स्थितियों में डबल डिस्पैच का उपयोग कर सकता है:
* वस्तुओं के मिश्रित सेट को क्रमबद्ध करना: एल्गोरिदम के लिए आवश्यक है कि वस्तुओं की एक सूची को कुछ विहित क्रम में क्रमबद्ध किया जाए। यह निर्णय लेने के लिए कि क्या एक तत्व दूसरे तत्व से पहले आता है, दोनों प्रकार के ज्ञान और संभवतः क्षेत्रों के कुछ सबसेट की आवश्यकता होती है।
* वस्तुओं के मिश्रित सेट को क्रमबद्ध करना: एल्गोरिदम के लिए आवश्यक है कि वस्तुओं की सूची को कुछ विहित क्रम में क्रमबद्ध किया जाए। यह निर्णय लेने के लिए कि क्या तत्व दूसरे तत्व से पहले आता है, दोनों टाइप के ज्ञान और संभवतः क्षेत्रों के कुछ सबसेट की आवश्यकता होती है।
* अनुकूली टकराव एल्गोरिदम के लिए आमतौर पर आवश्यकता होती है कि विभिन्न वस्तुओं के बीच टकराव को अलग-अलग तरीकों से नियंत्रित किया जाए। एक विशिष्ट उदाहरण खेल के माहौल में है जहां एक अंतरिक्ष यान और एक क्षुद्रग्रह के बीच टकराव की गणना एक अंतरिक्ष यान और एक अंतरिक्ष स्टेशन के बीच टकराव से अलग तरीके से की जाती है।<ref>More Effective C++ by Scott Meyers(Addison-Wesley, 1996)</ref>
* अनुकूली कोलिजन एल्गोरिदम के लिए सामान्यतः आवश्यकता होती है कि विभिन्न वस्तुओं के बीच कोलिजन को अलग-अलग विधियों से नियंत्रित किया जाए। विशिष्ट उदाहरण खेल के स्थिति में है जहां अंतरिक्ष यान और क्षुद्रग्रह के बीच कोलिजन की गणना अंतरिक्ष यान और अंतरिक्ष स्टेशन के बीच कोलिजन से अलग विधियों से की जाती है।<ref>More Effective C++ by Scott Meyers(Addison-Wesley, 1996)</ref>
* पेंटिंग एल्गोरिदम जिन्हें ओवरलैपिंग [[स्प्राइट (कंप्यूटर ग्राफिक्स)]] के प्रतिच्छेदन बिंदुओं को एक अलग तरीके से प्रस्तुत करने की आवश्यकता होती है।
* पेंटिंग एल्गोरिदम जिन्हें ओवरलैपिंग [[स्प्राइट (कंप्यूटर ग्राफिक्स)]] के प्रतिच्छेदन बिंदुओं को अलग विधियों से प्रस्तुत करने की आवश्यकता होती है।
* कार्मिक प्रबंधन प्रणालियाँ विभिन्न कर्मियों को विभिन्न प्रकार की नौकरियाँ भेज सकती हैं। <code>schedule</code> एल्गोरिदम जो एक व्यक्ति को अकाउंटेंट के रूप में टाइप की गई वस्तु और इंजीनियरिंग के रूप में टाइप की गई एक नौकरी की वस्तु देता है, उस नौकरी के लिए उस व्यक्ति की शेड्यूलिंग को अस्वीकार कर देता है।
* कार्मिक प्रबंधन प्रणालियाँ विभिन्न कर्मियों को विभिन्न टाइप की नौकरियाँ भेज सकती हैं। A <code>schedule</code> एल्गोरिदम जो व्यक्ति को अकाउंटेंट के रूप में टाइप की गई वस्तु और इंजीनियरिंग के रूप में टाइप की गई नौकरी की वस्तु देता है, उस नौकरी के लिए उस व्यक्ति की शेड्यूलिंग को अस्वीकार कर देता है।
* इवेंट हैंडलिंग सिस्टम जो सही इवेंट हैंडलिंग रूटीन को कॉल करने के लिए इवेंट प्रकार और रिसेप्टर ऑब्जेक्ट के प्रकार दोनों का उपयोग करते हैं।
* इवेंट हैंडलिंग प्रणाली जो सही इवेंट हैंडलिंग रूटीन को कॉल करने के लिए इवेंट टाइप और रिसेप्टर ऑब्जेक्ट के टाइप दोनों का उपयोग करते हैं।
* ताला और चाबी प्रणालियाँ जहाँ कई प्रकार के ताले और कई प्रकार की चाबियाँ होती हैं और प्रत्येक प्रकार की चाबी कई प्रकार के ताले खोलती है। आपको न केवल इसमें शामिल वस्तुओं के प्रकारों को जानने की आवश्यकता है, बल्कि किसी विशेष कुंजी के बारे में जानकारी का सबसेट जो यह देखने के लिए प्रासंगिक है कि क्या कोई विशेष कुंजी किसी विशेष लॉक को खोलती है, विभिन्न लॉक प्रकारों के बीच भिन्न होती है।
* ताला और कुंजी प्रणालियाँ जहाँ कई टाइप के ताले और कई टाइप की कीस होती हैं और प्रत्येक टाइप की कुंजी कई टाइप के ताले खोलती है। आपको न केवल इसमें सम्मिलित वस्तुओं के टाइपों को जानने की आवश्यकता है, बल्कि किसी विशेष कुंजी के बारे में जानकारी का सबसेट जो यह देखने के लिए प्रासंगिक है कि क्या कोई विशेष कुंजी किसी विशेष लॉक को खोलती है, विभिन्न लॉक टाइपों के बीच भिन्न होती है।


==एक सामान्य मुहावरा==
==सामान्य मुहावरा==
सामान्य मुहावरा, जैसा कि ऊपर प्रस्तुत उदाहरणों में है, यह है कि उपयुक्त एल्गोरिदम का चयन रनटाइम पर कॉल के तर्क प्रकारों पर आधारित होता है। इसलिए कॉल सभी सामान्य अतिरिक्त प्रदर्शन लागतों के अधीन है जो कॉल के गतिशील रिज़ॉल्यूशन से जुड़ी हैं, आमतौर पर केवल एकल विधि प्रेषण का समर्थन करने वाली भाषा की तुलना में अधिक। उदाहरण के लिए, [[C++]] में, एक डायनेमिक फ़ंक्शन कॉल को आमतौर पर एकल [[ऑफसेट (कंप्यूटर विज्ञान)]] गणना द्वारा हल किया जाता है - जो संभव है क्योंकि कंपाइलर ऑब्जेक्ट की वर्चुअल विधि तालिका में फ़ंक्शन का स्थान जानता है और इसलिए ऑफसेट की सांख्यिकीय गणना कर सकता है। डबल डिस्पैच का समर्थन करने वाली भाषा में, यह थोड़ा अधिक महंगा है, क्योंकि कंपाइलर को रनटाइम पर विधि तालिका में विधि के ऑफसेट की गणना करने के लिए कोड उत्पन्न करना होगा, जिससे समग्र [[निर्देश पथ की लंबाई]] बढ़ जाएगी (एक ऐसी राशि जो फ़ंक्शन में कॉल की कुल संख्या से अधिक नहीं होने की संभावना है, जो बहुत महत्वपूर्ण नहीं हो सकती है)
सामान्य मुहावरा, जैसा कि ऊपर प्रस्तुत उदाहरणों में है, यह है कि उपयुक्त एल्गोरिदम का चयन रनटाइम पर कॉल के तर्क टाइपों पर आधारित होता है। इसलिए कॉल सभी सामान्य अतिरिक्त प्रदर्शन लागतों के अधीन है जो कॉल के गतिशील रिज़ॉल्यूशन से जुड़ी हैं, सामान्यतः केवल एकल विधि डिस्पैच का समर्थन करने वाली लैंग्वेज की तुलना में अधिक। उदाहरण के लिए, [[C++]] में, डायनेमिक फंक्शन कॉल को सामान्यतः एकल [[ऑफसेट (कंप्यूटर विज्ञान)]] गणना द्वारा हल किया जाता है - जो संभव है क्योंकि कंपाइलर ऑब्जेक्ट की वर्चुअल विधि तालिका में फंक्शन का स्थान जानता है और इसलिए ऑफसेट की सांख्यिकीय गणना कर सकता है। डबल डिस्पैच का समर्थन करने वाली लैंग्वेज में, यह थोड़ा अधिक बहुमूल्य है, क्योंकि कंपाइलर को रनटाइम पर विधि तालिका में विधि के ऑफसेट की गणना करने के लिए कोड उत्पन्न करना होगा, जिससे समग्र [[निर्देश पथ की लंबाई]] बढ़ जाएगी (ऐसी राशि जो फंक्शन में कॉल की कुल संख्या से अधिक नहीं होने की संभावना है, जो बहुत महत्वपूर्ण नहीं हो सकती है।)


==रूबी में उदाहरण==
==रूबी में उदाहरण==
एक सामान्य उपयोग का मामला डिस्प्ले पोर्ट पर एक ऑब्जेक्ट प्रदर्शित करना है जो एक स्क्रीन या प्रिंटर हो सकता है, या पूरी तरह से कुछ और जो अभी तक मौजूद नहीं है। यह उन विभिन्न मीडिया से निपटने का एक अनुभवहीन कार्यान्वयन है।
सामान्य उपयोग की स्थितियां डिस्प्ले पोर्ट पर ऑब्जेक्ट प्रदर्शित करना है जो स्क्रीन या प्रिंटर हो सकता है, या पूरी तरह से कुछ और जो अभी तक उपस्थित नहीं है। यह उन विभिन्न मीडिया से निपटने का अनुभवहीन कार्यान्वयन है।


<syntaxhighlight lang="ruby">
<syntaxhighlight lang="ruby">
Line 40: Line 40:
end
end
</syntaxhighlight>
</syntaxhighlight>
इसे ओवल, ट्राइएंगल और किसी भी अन्य वस्तु के लिए लिखने की आवश्यकता होगी जो खुद को एक माध्यम पर प्रदर्शित करना चाहता है, और यदि एक नए प्रकार का पोर्ट बनाना है तो सभी को फिर से लिखना होगा। समस्या यह है कि बहुरूपता की एक से अधिक डिग्री मौजूद हैं: एक किसी ऑब्जेक्ट पर डिस्प्ले_ऑन विधि भेजने के लिए और दूसरा प्रदर्शित करने के लिए सही कोड (या विधि) का चयन करने के लिए।
इसे ओवल, ट्राइएंगल और किसी भी अन्य वस्तु के लिए लिखने की आवश्यकता होगी जो स्वयं को माध्यम पर प्रदर्शित करना चाहता है, और यदि नए टाइप का पोर्ट बनाना है तो सभी को फिर से लिखना होगा। समस्या यह है कि बहुरूपता की एक से अधिक डिग्री उपस्थित हैं: किसी ऑब्जेक्ट पर display_on विधि भेजने के लिए और दूसरा प्रदर्शित करने के लिए सही कोड (या विधि) का चयन करने के लिए उपथित है।


एक अधिक स्वच्छ और अधिक रख-रखाव योग्य समाधान यह है कि इस बार माध्यम पर वस्तु को प्रदर्शित करने के लिए सही विधि का चयन करने के लिए दूसरा प्रेषण किया जाए:
अधिक स्वच्छ और अधिक रख-रखाव योग्य समाधान यह है कि इस बार माध्यम पर वस्तु को प्रदर्शित करने के लिए सही विधि का चयन करने के लिए दूसरा डिस्पैच किया जाए:


<syntaxhighlight lang="ruby">
<syntaxhighlight lang="ruby">
Line 82: Line 82:




==C++== में दोहरा प्रेषण
 
पहली नज़र में, दोहरा प्रेषण [[फ़ंक्शन ओवरलोडिंग]] का एक स्वाभाविक परिणाम प्रतीत होता है। फ़ंक्शन ओवरलोडिंग कॉल किए गए फ़ंक्शन को तर्क के प्रकार पर निर्भर करने की अनुमति देता है। हालाँकि, फ़ंक्शन ओवरलोडिंग, [[नाम मंगलिंग]] का उपयोग करके संकलन समय पर किया जाता है, जहां फ़ंक्शन का आंतरिक नाम तर्क के प्रकार को एन्कोड करता है। उदाहरण के लिए, एक फ़ंक्शन <code>foo(int)</code> आंतरिक रूप से बुलाया जा सकता है{{mono|__foo_i}} और फ़ंक्शन <code>foo(double)</code> बुलाया जा सकता है{{mono|__foo_d}}. इस प्रकार, कोई नाम टकराव नहीं है, और कोई वर्चुअल टेबल लुकअप नहीं है। इसके विपरीत, डायनेमिक डिस्पैच कॉलिंग ऑब्जेक्ट के प्रकार पर आधारित होता है, जिसका अर्थ है कि यह फ़ंक्शन ओवरलोडिंग के बजाय [[आभासी कार्य]] (ओवरराइडिंग) का उपयोग करता है, और इसके परिणामस्वरूप एक व्यवहार्य लुकअप होता है। किसी गेम में टकराव के C++ में लिखे गए निम्नलिखित उदाहरण पर विचार करें:
=== C++ में डबल डिस्पैच ===
पहली दृष्टी में, डबल डिस्पैच [[फ़ंक्शन ओवरलोडिंग|फंक्शन ओवरलोडिंग]] का स्वाभाविक परिणाम प्रतीत होता है। फंक्शन ओवरलोडिंग कॉल किए गए फंक्शन को तर्क के टाइप पर निर्भर करने की अनुमति देता है। चूँकि, फंक्शन ओवरलोडिंग, [[नाम मंगलिंग]] का उपयोग करके संकलन समय पर किया जाता है, जहां फंक्शन का आंतरिक नाम तर्क के टाइप को एन्कोड करता है। उदाहरण के लिए फंक्शन <code>foo(int)</code> को आंतरिक रूप से {{mono|__foo_i}} बुलाया जा सकता है और फंक्शन <code>foo(double)</code> को {{mono|__foo_d}} बुलाया जा सकता है। इस टाइप, कोई नाम कोलिजन नहीं है, और कोई वर्चुअल टेबल लुकअप नहीं है। इसके विपरीत, डायनेमिक डिस्पैच कॉलिंग ऑब्जेक्ट के टाइप पर आधारित होता है, जिसका अर्थ है कि यह फंक्शन ओवरलोडिंग के अतिरिक्त [[आभासी कार्य]] (ओवरराइडिंग) का उपयोग करता है, और इसके परिणामस्वरूप व्यवहार्य लुकअप होता है। किसी गेम में कोलिजन के C++ में लिखे गए निम्नलिखित उदाहरण पर विचार करें:
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
class SpaceShip {};
class SpaceShip {};
Line 114: Line 115:
ApolloSpacecraft theApolloSpacecraft;
ApolloSpacecraft theApolloSpacecraft;
</syntaxhighlight>
</syntaxhighlight>
फिर, फ़ंक्शन ओवरलोडिंग के कारण,
फिर, फंक्शन ओवरलोडिंग के कारण,
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
theAsteroid.CollideWith(theSpaceShip);  
theAsteroid.CollideWith(theSpaceShip);  
theAsteroid.CollideWith(theApolloSpacecraft);  
theAsteroid.CollideWith(theApolloSpacecraft);  
</syntaxhighlight>
</syntaxhighlight>
क्रमशः प्रिंट करेगा, <code>Asteroid hit a SpaceShip</code> और <code>Asteroid hit an ApolloSpacecraft</code>, बिना किसी गतिशील प्रेषण का उपयोग किए। आगे:
क्रमशः <code>Asteroid hit a SpaceShip</code> और <code>Asteroid hit an ApolloSpacecraft</code> , बिना किसी गतिशील डिस्पैच का उपयोग किए प्रिंट करेगा। आगे:
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
ExplodingAsteroid theExplodingAsteroid;
ExplodingAsteroid theExplodingAsteroid;
theExplodingAsteroid.CollideWith(theSpaceShip);  
theExplodingAsteroid.CollideWith(theSpaceShip);  
theExplodingAsteroid.CollideWith(theApolloSpacecraft);
theExplodingAsteroid.CollideWith(theApolloSpacecraft);
</syntaxhighlight> छापूंगा <code>ExplodingAsteroid hit a SpaceShip</code> और <code>ExplodingAsteroid hit an ApolloSpacecraft</code> क्रमशः, फिर से गतिशील प्रेषण के बिना।
</syntaxhighlight> <code>ExplodingAsteroid hit a SpaceShip</code> और <code>ExplodingAsteroid hit an ApolloSpacecraft</code> फिर से गतिशील डिस्पैच के बिना क्रमशः प्रिंट हो जायेगा।


एक के संदर्भ में <code>Asteroid</code>, गतिशील प्रेषण का उपयोग किया जाता है, और यह कोड:
<code>Asteroid</code> के संदर्भ में, गतिशील डिस्पैच का उपयोग किया जाता है, और यह कोड:
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
Asteroid& theAsteroidReference = theExplodingAsteroid;
Asteroid& theAsteroidReference = theExplodingAsteroid;
Line 132: Line 133:
theAsteroidReference.CollideWith(theApolloSpacecraft);
theAsteroidReference.CollideWith(theApolloSpacecraft);
</syntaxhighlight>
</syntaxhighlight>
प्रिंट <code>ExplodingAsteroid hit a SpaceShip</code> और <code>ExplodingAsteroid hit an ApolloSpacecraft</code>, फिर से जैसी कि उम्मीद थी। हालाँकि, निम्नलिखित कोड इच्छानुसार काम नहीं करता है:
प्रिंट <code>ExplodingAsteroid hit a SpaceShip</code> और <code>ExplodingAsteroid hit an ApolloSpacecraft</code>, फिर से जैसी कि आशा थी। चूँकि, निम्नलिखित कोड इच्छानुसार काम नहीं करता है:
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
SpaceShip& theSpaceShipReference = theApolloSpacecraft;
SpaceShip& theSpaceShipReference = theApolloSpacecraft;
Line 138: Line 139:
theAsteroidReference.CollideWith(theSpaceShipReference);
theAsteroidReference.CollideWith(theSpaceShipReference);
</syntaxhighlight>
</syntaxhighlight>
वांछित व्यवहार इन कॉलों को उस फ़ंक्शन से बांधना है जो लेता है <code>theApolloSpacecraft</code> इसके तर्क के रूप में, क्योंकि यह चर का तात्कालिक प्रकार है, जिसका अर्थ है कि अपेक्षित आउटपुट होगा <code>Asteroid hit an ApolloSpacecraft</code> और <code>ExplodingAsteroid hit an ApolloSpacecraft</code>. हालाँकि, आउटपुट वास्तव में है <code>Asteroid hit a SpaceShip</code> और <code>ExplodingAsteroid hit a SpaceShip</code>. समस्या यह है कि, जबकि वर्चुअल फ़ंक्शन C++ में गतिशील रूप से भेजे जाते हैं, फ़ंक्शन ओवरलोडिंग स्थिर रूप से की जाती है।
वांछित व्यवहार इन कॉलों को उस फंक्शन से बांधना है, जो <code>theApolloSpacecraft</code> इसके तर्क के रूप में लेता है, क्योंकि यह चर का तात्कालिक टाइप है, जिसका अर्थ है कि अपेक्षित आउटपुट <code>Asteroid hit an ApolloSpacecraft</code> और <code>ExplodingAsteroid hit an ApolloSpacecraft</code> होगा। चूँकि, आउटपुट वास्तव में <code>Asteroid hit a SpaceShip</code> और <code>ExplodingAsteroid hit a SpaceShip</code> है। समस्या यह है कि, जबकि वर्चुअल फंक्शन C++ में गतिशील रूप से भेजे जाते हैं, तो फंक्शन ओवरलोडिंग स्थिर रूप से की जाती है।


ऊपर वर्णित समस्या को दोहरे प्रेषण का [[अनुकरण]] करके हल किया जा सकता है, उदाहरण के लिए [[आगंतुक पैटर्न]] का उपयोग करके। मान लीजिए कि मौजूदा कोड को बढ़ाया गया है ताकि दोनों <code>SpaceShip</code> और <code>ApolloSpacecraft</code> फ़ंक्शन दिया गया है
ऊपर वर्णित समस्या को दोहरे डिस्पैच का [[अनुकरण]] करके हल किया जा सकता है, उदाहरण के लिए [[आगंतुक पैटर्न|विजिटर पैटर्न]] का उपयोग करके। मान लीजिए कि उपस्थिता कोड को बढ़ाया गया है जिससे दोनों <code>SpaceShip</code> और <code>ApolloSpacecraft</code> फंक्शन दिया गया है
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
virtual void CollideWith(Asteroid& inAsteroid) {
virtual void CollideWith(Asteroid& inAsteroid) {
Line 146: Line 147:
}
}
</syntaxhighlight>
</syntaxhighlight>
फिर, जबकि पिछला उदाहरण अभी भी सही ढंग से काम नहीं करता है, कॉल को फिर से फ्रेम करना ताकि अंतरिक्ष यान एजेंट हो, हमें वांछित व्यवहार देता है:
फिर, जबकि पिछला उदाहरण अभी भी सही ढंग से काम नहीं करता है, कॉल को फिर से फ्रेम करना जिससे अंतरिक्ष यान एजेंट हो, हमें वांछित व्यवहार देता है:
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
SpaceShip& theSpaceShipReference = theApolloSpacecraft;
SpaceShip& theSpaceShipReference = theApolloSpacecraft;
Line 153: Line 154:
theSpaceShipReference.CollideWith(theAsteroidReference);
theSpaceShipReference.CollideWith(theAsteroidReference);
</syntaxhighlight>
</syntaxhighlight>
यह प्रिंट कर लेता है <code>Asteroid hit an ApolloSpacecraft</code> और <code>ExplodingAsteroid hit an ApolloSpacecraft</code>, आशा के अनुसार। कुंजी वह है <code>theSpaceShipReference.CollideWith(theAsteroidReference);</code> रन टाइम पर निम्न कार्य करता है:
यह <code>Asteroid hit an ApolloSpacecraft</code> और <code>ExplodingAsteroid hit an ApolloSpacecraft</code> प्रिंट कर लेता है, आशा के अनुसार कुंजी <code>theSpaceShipReference.CollideWith(theAsteroidReference);</code> रन टाइम पर निम्न कार्य करता है:
# <code>theSpaceShipReference</code> एक संदर्भ है, इसलिए C++ vtable में सही विधि ढूंढता है। इस मामले में, यह कॉल करेगा <code>ApolloSpacecraft::CollideWith(Asteroid&)</code>.
# <code>theSpaceShipReference</code> संदर्भ है, इसलिए C++ vtable में सही विधि ढूंढता है। इस स्थितियों में, यह <code>ApolloSpacecraft::CollideWith(Asteroid&)</code> कॉल करेगा।
# अंदर <code>ApolloSpacecraft::CollideWith(Asteroid&)</code>, <code>inAsteroid</code> एक संदर्भ है, इसलिए <code>inAsteroid.CollideWith(*this)</code> इसके परिणामस्वरूप एक और वेटेबल लुकअप होगा। इस मामले में, <code>inAsteroid</code> एक का संदर्भ है <code>ExplodingAsteroid</code> इसलिए <code>ExplodingAsteroid::CollideWith(ApolloSpacecraft&)</code> बुलाया जाएगा।
# अंदर <code>ApolloSpacecraft::CollideWith(Asteroid&)</code>, <code>inAsteroid</code> संदर्भ है, इसलिए <code>inAsteroid.CollideWith(*this)</code> इसके परिणामस्वरूप एक और वेटेबल लुकअप होगा। इस स्थितियों में, <code>inAsteroid</code> का संदर्भ <code>ExplodingAsteroid</code> है इसलिए <code>ExplodingAsteroid::CollideWith(ApolloSpacecraft&)</code> बुलाया जाएगा।


==सी#== में डबल प्रेषण
=== C# में डबल डिस्पैच ===
सी शार्प (प्रोग्रामिंग भाषा)|सी# में, किसी तर्क को स्वीकार करते हुए एक इंस्टेंस विधि को कॉल करते समय, विज़िटर पैटर्न को नियोजित किए बिना एकाधिक प्रेषण प्राप्त किया जा सकता है। यह तर्क को गतिशील बनाते हुए पारंपरिक बहुरूपता का उपयोग करके किया जाता है।<ref>{{cite web |url=https://msdn.microsoft.com/en-us/library/dd264736.aspx |title=टाइप डायनामिक का उपयोग करना (सी# प्रोग्रामिंग गाइड)|publisher=Microsoft |date=30 Sep 2009 |website=Microsoft Developer Network |access-date=25 May 2016 |quote=...&nbsp;Overload resolution occurs at run time instead of at compile time if one or more of the arguments in a method call have the type dynamic&nbsp;...}}</ref> रन-टाइम बाइंडर रन-टाइम पर उचित विधि ओवरलोड का चयन करेगा। यह निर्णय ऑब्जेक्ट इंस्टेंस के रन-टाइम प्रकार (बहुरूपता) के साथ-साथ तर्क के रन-टाइम प्रकार को भी ध्यान में रखेगा।
(प्रोग्रामिंग लैंग्वेज) C# में, किसी तर्क को स्वीकार करते हुए इंस्टेंस विधि को कॉल करते समय, विज़िटर पैटर्न को नियोजित किए बिना मल्टीप्ल डिस्पैच प्राप्त किया जा सकता है। यह तर्क को गतिशील बनाते हुए पारंपरिक बहुरूपता का उपयोग करके किया जाता है।<ref>{{cite web |url=https://msdn.microsoft.com/en-us/library/dd264736.aspx |title=टाइप डायनामिक का उपयोग करना (सी# प्रोग्रामिंग गाइड)|publisher=Microsoft |date=30 Sep 2009 |website=Microsoft Developer Network |access-date=25 May 2016 |quote=...&nbsp;Overload resolution occurs at run time instead of at compile time if one or more of the arguments in a method call have the type dynamic&nbsp;...}}</ref> रन-टाइम बाइंडर रन-टाइम पर उचित विधि ओवरलोड का चयन करेगा। यह निर्णय ऑब्जेक्ट इंस्टेंस के रन-टाइम टाइप (बहुरूपता) के साथ-साथ तर्क के रन-टाइम टाइप को भी ध्यान में रखेगा।


== एफिल में दोहरा प्रेषण ==
== एफिल में डबल डिस्पैच ==
[[एफिल (प्रोग्रामिंग भाषा)]] प्रोग्रामिंग भाषा एजेंटों की अवधारणा को डबल-डिस्पैच समस्या पर सहन करने के लिए ला सकती है। नीचे दिया गया उदाहरण एजेंट भाषा निर्माण को डबल-डिस्पैच समस्या पर लागू करता है।
[[एफिल (प्रोग्रामिंग भाषा)|एफिल (प्रोग्रामिंग लैंग्वेज)]] प्रोग्रामिंग लैंग्वेज एजेंटों की अवधारणा को डबल-डिस्पैच समस्या पर सहन करने के लिए ला सकती है। नीचे दिया गया उदाहरण एजेंट लैंग्वेज निर्माण को डबल-डिस्पैच समस्या पर प्रयुक्त करता है।


आकृति के विभिन्न रूपों और सतह को चित्रित करने वाले एक समस्या डोमेन पर विचार करें, जिस पर आकृति बनाई जाए। SHAPE और SURFACE दोनों अपने आप में `ड्रा' नामक फ़ंक्शन के बारे में जानते हैं, लेकिन एक दूसरे में नहीं। हम चाहते हैं कि दो प्रकार की वस्तुएं विज़िटर पैटर्न का उपयोग करके डबल-डिस्पैच में एक-दूसरे के साथ सह-भिन्न रूप से बातचीत करें।
आकृति के विभिन्न रूपों और सतह को चित्रित करने वाले समस्या डोमेन पर विचार करें, जिस पर आकृति बनाई जाए। SHAPE और SURFACE दोनों अपने आप में `draw' नामक फंक्शन के बारे में जानते हैं, लेकिन दूसरे में नहीं हम चाहते हैं कि दो टाइप की वस्तुएं विज़िटर पैटर्न का उपयोग करके डबल-डिस्पैच में एक-दूसरे के साथ सह-भिन्न रूप से वार्तालाप करें। चुनौती बहुरूपी सतह को अपने ऊपर बहुरूपी आकार बनाने के लिए प्राप्त करना है।
 
चुनौती एक बहुरूपी सतह को अपने ऊपर एक बहुरूपी आकार बनाने के लिए प्राप्त करना है।


=== आउटपुट ===
=== आउटपुट ===
नीचे दिया गया आउटपुट उदाहरण दो SURFACE विज़िटर ऑब्जेक्ट्स के परिणाम दिखाता है जिन्हें पॉलीमॉर्फिक SHAPE ऑब्जेक्ट्स की सूची में पॉलीमॉर्फिक रूप से पारित किया गया है। विज़िटर कोड पैटर्न केवल सामान्य रूप से SHAPE और SURFACE के बारे में जानता है, किसी विशिष्ट प्रकार के बारे में नहीं। इसके बजाय, कोड इन दो स्थगित वर्गों और उनके वंशजों के बीच अत्यधिक लचीले सह-संस्करण संबंध प्राप्त करने के लिए रन-टाइम बहुरूपता और एजेंटों के यांत्रिकी पर निर्भर करता है।
नीचे दिया गया आउटपुट उदाहरण दो SURFACE विज़िटर ऑब्जेक्ट्स के परिणाम दिखाता है जिन्हें पॉलीमॉर्फिक SHAPE ऑब्जेक्ट्स की सूची में पॉलीमॉर्फिक रूप से पारित किया गया है। विज़िटर कोड पैटर्न केवल सामान्य रूप से SHAPE और SURFACE के बारे में जानता है, किसी विशिष्ट टाइप के बारे में नहीं। इसके अतिरिक्त, कोड इन दो स्थगित वर्गों और उनके डिसेंडेन्ट्स के बीच अत्यधिक लचीले सह-संस्करण संबंध प्राप्त करने के लिए रन-टाइम बहुरूपता और एजेंटों के यांत्रिकी पर निर्भर करता है।<syntaxhighlight>
 
draw a red POLYGON on ETCHASKETCH
चित्रित करो {{colors|white|red|red}} ETCHASKETCH पर बहुभुज
draw a red POLYGON on GRAFFITI_WALL
चित्रित करो {{colors|white|red|red}} भित्तिचित्र दीवार पर बहुभुज बनाएं {{colors|white|grey|grey}} ETCHASKETCH पर आयत
draw a grey RECTANGLE on ETCHASKETCH
चित्रित करो {{colors|white|grey|grey}} भित्तिचित्र दीवार पर आयत बनाएं {{colors|white|green|green}} ETCHASKETCH पर चतुर्भुज
draw a grey RECTANGLE on GRAFFITI_WALL
चित्रित करो {{colors|white|green|green}} भित्तिचित्र दीवार पर चतुर्भुज एक चित्र बनाएं {{colors|white|blue|blue}} ETCHASKETCH पर समांतर चतुर्भुज
draw a green QUADRILATERAL on ETCHASKETCH
चित्रित करो {{colors|white|blue|blue}} भित्तिचित्र दीवार पर समांतर चतुर्भुज बनाएं {{colors|black|yellow|yellow}} ETCHASKETCH पर बहुभुज
draw a green QUADRILATERAL on GRAFFITI_WALL
चित्रित करो {{colors|black|yellow|yellow}} भित्तिचित्र दीवार पर बहुभुज बनाएं {{colors|white|purple|purple}} ETCHASKETCH पर आयत
draw a blue PARALLELOGRAM on ETCHASKETCH
  चित्रित करो {{colors|white|purple|purple}} भित्तिचित्र दीवार पर आयत
draw a blue PARALLELOGRAM on GRAFFITI_WALL
draw a yellow POLYGON on ETCHASKETCH
draw a yellow POLYGON on GRAFFITI_WALL
draw a purple RECTANGLE on ETCHASKETCH
draw a purple RECTANGLE on GRAFFITI_WALL
</syntaxhighlight>
   


=== सेटअप ===
=== सेटअप ===
SHAPE या SURFACE को देखने से पहले, हमें अपने डबल-डिस्पैच के उच्च स्तरीय डिकौपल्ड उपयोग की जांच करने की आवश्यकता है।
SHAPE या SURFACE को देखने से पहले, हमें अपने डबल-डिस्पैच के उच्च स्तरीय डिकौपल्ड उपयोग की जांच करने की आवश्यकता है।


==== आगंतुक पैटर्न ====
==== विज़िटर पैटर्न ====
विज़िटर पैटर्न एक विज़िटर ऑब्जेक्ट के माध्यम से डेटा संरचना के तत्वों (उदाहरण के लिए सूची, पेड़ और इसी तरह) पर जाकर बहुरूपी रूप से काम करता है, विज़िट की गई लक्ष्य संरचना में बहुरूपी तत्व ऑब्जेक्ट के विरुद्ध कुछ कार्रवाई (कॉल या एजेंट) लागू करता है।
विज़िटर पैटर्न विज़िटर ऑब्जेक्ट के माध्यम से डेटा संरचना के तत्वों (उदाहरण के लिए सूची, पेड़ और इसी तरह) पर जाकर बहुरूपी रूप से काम करता है, विज़िट की गई लक्ष्य संरचना में बहुरूपी तत्व ऑब्जेक्ट के विरुद्ध कुछ कार्रवाई (कॉल या एजेंट) प्रयुक्त करता है।


नीचे दिए गए हमारे उदाहरण में, हम बहुरूपी SHAPE वस्तुओं की एक सूची बनाते हैं, उनमें से प्रत्येक को एक बहुरूपी सतह के साथ देखते हैं, और सतह पर आकृति बनाने के लिए कहते हैं।
नीचे दिए गए हमारे उदाहरण में, हम बहुरूपी SHAPE वस्तुओं की सूची बनाते हैं, उनमें से प्रत्येक को बहुरूपी सतह के साथ देखते हैं, और सतह पर आकृति बनाने के लिए कहते हैं।<syntaxhighlight>
make
-- Print shapes on surfaces.
local
l_shapes: ARRAYED_LIST [SHAPE]
l_surfaces: ARRAYED_LIST [SURFACE]
do
create l_shapes.make (6)
l_shapes.extend (create {POLYGON}.make_with_color ("red"))
l_shapes.extend (create {RECTANGLE}.make_with_color ("grey"))
l_shapes.extend (create {QUADRILATERAL}.make_with_color ("green"))
l_shapes.extend (create {PARALLELOGRAM}.make_with_color ("blue"))
l_shapes.extend (create {POLYGON}.make_with_color ("yellow"))
l_shapes.extend (create {RECTANGLE}.make_with_color ("purple"))


<सिंटैक्सहाइलाइट लैंग= एफिल लाइन हाइलाइट= 23 >
create l_surfaces.make (2)
निर्माण
l_surfaces.extend (create {ETCHASKETCH}.make)
-- सतहों पर आकृतियाँ मुद्रित करें।
l_surfaces.extend (create {GRAFFITI_WALL}.make)
स्थानीय
l_आकार: ARRAYED_LIST [आकार]
l_सतहें: ARRAYED_LIST [सतह]
करना
l_shapes.बनाएँ (6)
l_shapes.extend ({POLYGON} बनाएं.make_with_color (लाल))
l_shapes.extend ({RECTANGLE} बनाएं.make_with_color (ग्रे))
l_shapes.extend (बनाएँ {QUADRILATERAL}.make_with_color (हरा))
l_shapes.extend ({PARALLELOGRAM} बनाएं.make_with_color (नीला))
l_shapes.extend (बनाएँ {POLYGON}.make_with_color (पीला))
l_shapes.extend ({RECTANGLE} बनाएं.make_with_color (बैंगनी))


l_surfaces.make बनाएँ (2)
across l_shapes as ic_shapes loop
l_surfaces.extend (बनाएं {ETCHASKETCH} बनाएं)
across l_surfaces as ic_surfaces loop
l_surfaces.extend ({GRAFFITI_WALL} बनाएं। बनाएं)
ic_surfaces.item.drawing_agent (ic_shapes.item.drawing_data_agent)
end
end
end
</syntaxhighlight>


l_shapes में ic_shapes लूप के रूप में
हम SHAPE और SURFACE वस्तुओं का संग्रह बनाकर प्रारंभ करते हैं। फिर हम सूचियों (SHAPE) में से एक पर पुनरावृत्ति करते हैं, जिससे दूसरे (SURFACE) के तत्वों को बारी-बारी से उनमें से प्रत्येक पर जाने की अनुमति मिलती है। उपरोक्त उदाहरण कोड में, SURFACE ऑब्जेक्ट SHAPE ऑब्जेक्ट पर जा रहे हैं।
l_surfaces के पार ic_surfaces लूप के रूप में
ic_surfaces.item.drawing_agent (ic_shapes.item.drawing_data_agent)
अंत
अंत
अंत
</सिंटैक्सहाइलाइट>
हम SHAPE और SURFACE वस्तुओं का एक संग्रह बनाकर शुरुआत करते हैं। फिर हम सूचियों (SHAPE) में से एक पर पुनरावृत्ति करते हैं, जिससे दूसरे (SURFACE) के तत्वों को बारी-बारी से उनमें से प्रत्येक पर जाने की अनुमति मिलती है। उपरोक्त उदाहरण कोड में, SURFACE ऑब्जेक्ट SHAPE ऑब्जेक्ट पर जा रहे हैं।


कोड {SURFACE} पर एक बहुरूपी कॉल करता है। 'ड्राइंग_एजेंट' के माध्यम से अप्रत्यक्ष रूप से ड्रा करें, जो डबल-डिस्पैच पैटर्न की पहली कॉल (डिस्पैच) है। यह एक अप्रत्यक्ष और बहुरूपी एजेंट (`ड्राइंग_डेटा_एजेंट') पास करता है, जिससे हमारे विज़िटर कोड को केवल दो चीजों के बारे में जानने की अनुमति मिलती है:
कोड {SURFACE} पर बहुरूपी कॉल करता है। Drawing_agent के माध्यम से अप्रत्यक्ष रूप से ड्रा करें, जो डबल-डिस्पैच पैटर्न की पहली कॉल (डिस्पैच) है। यह अप्रत्यक्ष और बहुरूपी एजेंट (`drawing_data_agent') पास करता है, जिससे हमारे विज़िटर कोड को केवल दो चीजों के बारे में जानने की अनुमति मिलती है:


* सतह का ड्राइंग एजेंट क्या है (उदाहरण के लिए लाइन #21 पर al_surface.drawing_agent)?
* सतह का ड्राइंग एजेंट क्या है (उदाहरण के लिए al_surface.drawing_agent on line #21)?
* आकृति का ड्राइंग डेटा एजेंट क्या है (उदाहरण के लिए लाइन #21 पर al_shape.drawing_data_agent)?
* आकृति का ड्राइंग डेटा एजेंट क्या है (उदाहरण के लिए al_shape.drawing_data_agent on line #21)?


चूँकि SURFACE और SHAPE दोनों ही अपने स्वयं के एजेंटों को परिभाषित करते हैं, इसलिए हमारे विज़िटर कोड को यह जानने से मुक्ति मिल जाती है कि बहुरूपी या अन्यथा, करने के लिए उपयुक्त कॉल क्या है। इनडायरेक्शन और डिकॉउलिंग का यह स्तर सी, सी++ और जावा जैसी अन्य सामान्य भाषाओं में किसी प्रकार के [[प्रतिबिंब (कंप्यूटर विज्ञान)]] या हस्ताक्षर मिलान के साथ फीचर ओवरलोडिंग को छोड़कर आसानी से प्राप्त नहीं किया जा सकता है।
चूँकि SURFACE और SHAPE दोनों ही अपने स्वयं के एजेंटों को परिभाषित करते हैं, इसलिए हमारे विज़िटर कोड को यह जानने से मुक्ति मिल जाती है कि बहुरूपी या अन्यथा, करने के लिए उपयुक्त कॉल क्या है। इनडायरेक्शन और डिकॉउलिंग का यह स्तर C, C++ और जावा जैसी अन्य सामान्य लैंग्वेजओं में किसी टाइप के [[प्रतिबिंब (कंप्यूटर विज्ञान)|रिफ्लेक्सन (कंप्यूटर विज्ञान)]] या हस्ताक्षर मिलान के साथ फीचर ओवरलोडिंग को छोड़कर सरलता से प्राप्त नहीं किया जा सकता है।


==== सतह ====
==== सतह ====
बहुरूपी कॉल के भीतर {SURFACE}.draw एक एजेंट के लिए कॉल है, जो डबल-डिस्पैच पैटर्न में दूसरी बहुरूपी कॉल या प्रेषण बन जाता है।
बहुरूपी कॉल के अन्दर {SURFACE}.draw एजेंट के लिए कॉल है, जो डबल-डिस्पैच पैटर्न में दूसरी बहुरूपी कॉल या डिस्पैच बन जाता है।


<syntaxhighlight lang="eiffel" line>
<syntaxhighlight lang="eiffel" line>
Line 258: Line 262:
end
end
</syntaxhighlight>
</syntaxhighlight>
पंक्ति #19 में एजेंट तर्क और पंक्ति #24 में कॉल दोनों बहुरूपी और वियुग्मित हैं। एजेंट को अलग कर दिया गया है क्योंकि {SURFACE}.draw फीचर को पता नहीं है कि `a_data_agent' किस वर्ग पर आधारित है। यह बताने का कोई तरीका नहीं है कि ऑपरेशन एजेंट किस वर्ग से लिया गया था, इसलिए इसे SHAPE या उसके वंशजों में से किसी एक से आना जरूरी नहीं है। यह अन्य भाषाओं की एकल विरासत, गतिशील और बहुरूपी बंधन पर एफिल एजेंटों का एक विशिष्ट लाभ है।
पंक्ति #19 में एजेंट तर्क और पंक्ति #24 में कॉल दोनों बहुरूपी और वियुग्मित हैं। एजेंट को अलग कर दिया गया है क्योंकि {SURFACE}.draw फीचर को पता नहीं है कि `a_data_agent' किस वर्ग पर आधारित है। यह बताने का कोई विधि नहीं है कि ऑपरेशन एजेंट किस वर्ग से लिया गया था, इसलिए इसे SHAPE या उसके डिसेंडेन्ट्स में से किसी एक से आना आवश्यक नहीं है। यह अन्य लैंग्वेजओं की एकल विरासत, गतिशील और बहुरूपी बंधन पर एफिल एजेंटों का विशिष्ट लाभ है।


रन-टाइम पर एजेंट गतिशील रूप से बहुरूपी होता है क्योंकि ऑब्जेक्ट को उसी क्षण बनाया जाता है, जब इसकी आवश्यकता होती है, गतिशील रूप से, जहां उस समय ऑब्जेक्टिफाइड रूटीन का संस्करण निर्धारित किया जाता है। एकमात्र दृढ़ता से बंधा हुआ ज्ञान एजेंट हस्ताक्षर के परिणाम प्रकार का है - अर्थात - दो तत्वों के साथ TUPLE नाम दिया गया है। हालाँकि, यह विशिष्ट आवश्यकता संलग्न सुविधा की मांग पर आधारित है (उदाहरण के लिए पंक्ति #25, SURFACE की 'ड्रा' सुविधा को पूरा करने के लिए TUPLE के नामित तत्वों का उपयोग करती है), जो आवश्यक है और इसे टाला नहीं गया है (और शायद नहीं भी किया जा सकता है)।
रन-टाइम पर एजेंट गतिशील रूप से बहुरूपी होता है क्योंकि ऑब्जेक्ट को उसी क्षण बनाया जाता है, जब इसकी आवश्यकता होती है, गतिशील रूप से, जहां उस समय ऑब्जेक्टिफाइड रूटीन का संस्करण निर्धारित किया जाता है। एकमात्र दृढ़ता से बंधा हुआ ज्ञान एजेंट हस्ताक्षर के परिणाम टाइप का है - अर्थात - दो तत्वों के साथ TUPLE नाम दिया गया है। चूँकि, यह विशिष्ट आवश्यकता संलग्न सुविधा की मांग पर आधारित है (उदाहरण के लिए पंक्ति #25, SURFACE की 'draw' सुविधा को पूरा करने के लिए TUPLE के नामित तत्वों का उपयोग करती है), जो आवश्यक है और इसे टाला नहीं गया है (और संभवतया नहीं भी किया जा सकता है)।


अंत में, ध्यान दें कि किसी भी ग्राहक को केवल 'ड्राइंग_एजेंट' सुविधा कैसे निर्यात की जाती है! इसका मतलब यह है कि विज़िटर पैटर्न कोड (जो इस वर्ग का एकमात्र ग्राहक है) को अपना काम पूरा करने के लिए केवल एजेंट के बारे में जानना होगा (उदाहरण के लिए विज़िट की गई वस्तुओं पर लागू सुविधा के रूप में एजेंट का उपयोग करना)।
अंत में, ध्यान दें कि किसी भी ग्राहक को केवल Drawing_agent सुविधा कैसे निर्यात की जाती है! इसका अर्थ यह है कि विज़िटर पैटर्न कोड (जो इस वर्ग का एकमात्र ग्राहक है) को अपना काम पूरा करने के लिए केवल एजेंट के बारे में जानना होगा (उदाहरण के लिए विज़िट की गई वस्तुओं पर प्रयुक्त सुविधा के रूप में एजेंट का उपयोग करना)।


==== आकार ====
==== आकार ====
SHAPE वर्ग के पास जो कुछ खींचा जाता है उसका आधार होता है (उदाहरण के लिए डेटा खींचना), शायद किसी सतह पर, लेकिन ऐसा होना ज़रूरी नहीं है। फिर से, एजेंट SHAPE के साथ सह-संस्करण संबंध को यथासंभव विघटित करने के लिए आवश्यक अप्रत्यक्ष और वर्ग अज्ञेयवादी प्रदान करते हैं।
SHAPE वर्ग के पास जो कुछ खींचा जाता है उसका आधार होता है (उदाहरण के लिए डेटा खींचना), संभवतया किसी सतह पर, लेकिन ऐसा होना आवश्यक नहीं है। फिर से, एजेंट SHAPE के साथ सह-संस्करण संबंध को यथासंभव विघटित करने के लिए आवश्यक अप्रत्यक्ष और वर्ग अज्ञेयवादी प्रदान करते हैं।


इसके अतिरिक्त, कृपया इस तथ्य पर ध्यान दें कि SHAPE किसी भी ग्राहक को पूरी तरह से निर्यात की गई सुविधा के रूप में केवल 'ड्राइंग_डेटा_एजेंट' प्रदान करता है। इसलिए, निर्माण के अलावा, SHAPE के साथ बातचीत करने का एकमात्र तरीका 'ड्राइंग_डेटा_एजेंट' की सुविधाओं के माध्यम से है, जिसका उपयोग किसी भी क्लाइंट द्वारा SHAPE के लिए अप्रत्यक्ष और बहुरूपी रूप से ड्राइंग डेटा इकट्ठा करने के लिए किया जाता है!
इसके अतिरिक्त, कृपया इस तथ्य पर ध्यान दें कि SHAPE किसी भी ग्राहक को पूरी तरह से निर्यात की गई सुविधा के रूप में केवल 'drawing_data_agent' प्रदान करता है। इसलिए, निर्माण के अतिरिक्त, SHAPE के साथ वार्तालाप करने का एकमात्र विधि 'drawing_data_agent' की सुविधाओं के माध्यम से है, जिसका उपयोग किसी भी क्लाइंट द्वारा SHAPE के लिए अप्रत्यक्ष और बहुरूपी रूप से ड्राइंग डेटा इकट्ठा करने के लिए किया जाता है!


<syntaxhighlight lang="eiffel" line>
<syntaxhighlight lang="eiffel" line>
Line 309: Line 313:


== क्लासिक अंतरिक्ष यान उदाहरण ==
== क्लासिक अंतरिक्ष यान उदाहरण ==
क्लासिक स्पेसशिप उदाहरण की एक भिन्नता में एक या एक से अधिक स्पेसशिप वस्तुएं दुष्ट क्षुद्रग्रहों और अंतरिक्ष स्टेशनों जैसी अन्य वस्तुओं से भरे ब्रह्मांड में घूम रही हैं। हम जो चाहते हैं वह हमारे काल्पनिक ब्रह्मांड में दो सह-परिवर्ती वस्तुओं के बीच मुठभेड़ों (उदाहरण के लिए संभावित टकराव) से निपटने के लिए एक डबल-डिस्पैच विधि है।
क्लासिक स्पेसशिप उदाहरण की भिन्नता में एक या एक से अधिक स्पेसशिप वस्तुएं रोग्यु क्षुद्रग्रहों और अंतरिक्ष स्टेशनों जैसी अन्य वस्तुओं से भरे ब्रह्मांड में घूम रही हैं। हम जो चाहते हैं वह हमारे काल्पनिक ब्रह्मांड में दो सह-परिवर्ती वस्तुओं के बीच मुठभेड़ों (उदाहरण के लिए संभावित कोलिजन) से निपटने के लिए डबल-डिस्पैच विधि है।
 
नीचे दिए गए उदाहरण में, हमारे यूएसएस एंटरप्राइज और यूएसएस एक्सेलसियर का आउटपुट भ्रमण होगा:
नीचे दिए गए उदाहरण में, हमारे यूएसएस एंटरप्राइज और यूएसएस एक्सेलसियर का आउटपुट भ्रमण होगा:
<syntaxhighlight lang="text">
<syntaxhighlight lang="text">
Line 327: Line 332:




=== आगंतुक ===
=== विजिटर ===
क्लासिक स्पेसशिप उदाहरण के लिए विज़िटर के पास एक डबल-डिस्पैच तंत्र भी है।
क्लासिक स्पेसशिप उदाहरण के लिए विज़िटर के पास डबल-डिस्पैच सिस्टम भी है।<syntaxhighlight>
<सिंटैक्सहाइलाइट लैंग= एफिल लाइन हाइलाइट= 35 >
make
निर्माण
-- Allow SPACESHIP objects to visit and move about in a universe.
- स्पेसशिप वस्तुओं को ब्रह्मांड में घूमने और घूमने की अनुमति दें।
local
स्थानीय
l_universe: ARRAYED_LIST [SPACE_OBJECT]
l_ब्रह्मांड: ARRAYED_LIST [SPACE_OBJECT]
l_enterprise,
एल_उद्यम,
l_excelsior: SPACESHIP
l_एक्सेलसियर: अंतरिक्ष यान
do
करना
create l_enterprise.make_with_name ("Enterprise", "A-001")
l_enterprise.make_with_name बनाएं (एंटरप्राइज़, A-001)
create l_excelsior.make_with_name ("Excelsior", "A-003")
l_excelsior.make_with_name बनाएं (एक्सेलसियर, A-003)
create l_universe.make (0)
एल_यूनिवर्स बनाएं। बनाएं (0)
l_universe.force (l_enterprise)
l_univers.force (l_enterprise)
l_universe.force (create {ASTEROID}.make_with_name ("Rogue 1", "A-002"))
l_univers.force (बनाएँ {ASTEROID}.make_with_name (दुष्ट 1, A-002))
l_universe.force (create {ASTEROID}.make_with_name ("Rogue 2", "A-003"))
l_univers.force (बनाएँ {ASTEROID}.make_with_name (दुष्ट 2, A-003))
l_universe.force (l_excelsior)
l_univers.force (l_excelsior)
l_universe.force (create {ASTEROID}.make_with_name ("Rogue 3", "A-004"))
l_univers.force (बनाएँ {ASTEROID}.make_with_name (दुष्ट 3, A-004))
l_universe.force (create {SPACESTATION}.make_with_name ("Deep Space 9", "A-005"))
l_univers.force (बनाएं {SPACESTATION}.make_with_name (डीप स्पेस 9, -005))
visit (l_enterprise, l_universe)
(l_enterprise, l_univers) पर जाएँ
l_enterprise.set_position ("A-002")
l_enterprise.set_position (A-002)
visit (l_enterprise, l_universe)
(l_enterprise, l_univers) पर जाएँ
l_enterprise.set_position ("A-003")
l_enterprise.set_position (A-003)
visit (l_enterprise, l_universe)
(l_enterprise, l_univers) पर जाएँ
l_enterprise.set_position ("A-004")
l_enterprise.set_position (A-004)
l_excelsior.set_position ("A-005")
l_excelsior.set_position (A-005)
visit (l_enterprise, l_universe)
(l_enterprise, l_univers) पर जाएँ
visit (l_excelsior, l_universe)
(l_excelsior, l_univers) पर जाएँ
l_enterprise.set_position ("A-005")
l_enterprise.set_position (A-005)
visit (l_enterprise, l_universe)
(l_enterprise, l_univers) पर जाएँ
end
अंत
feature {NONE} -- Implementation
सुविधा {कोई नहीं}--कार्यान्वयन
visit (a_object: SPACE_OBJECT; a_universe: ARRAYED_LIST [SPACE_OBJECT])
(a_object: SPACE_OBJECT; a_univers: ARRAYED_LIST [SPACE_OBJECT]) पर जाएँ
-- `a_object' visits `a_universe'.
-- `एक_वस्तु' `एक_ब्रह्मांड' का दौरा करती है।
do
करना
across a_universe as ic_universe loop
a_univers में ic_univers लूप के रूप में
check attached {SPACE_OBJECT} ic_universe.item as al_universe_object then
फिर संलग्न {SPACE_OBJECT} ic_univers.item को al_univers_object के रूप में जांचें
a_object.encounter_agent.call ([al_universe_object.sensor_data_agent])
a_object.encounter_agent.call ([al_univers_object.sensor_data_agent])
end
अंत
end
अंत
end
अंत
</syntaxhighlight>
</सिंटैक्सहाइलाइट>
 
डबल-डिस्पैच को पंक्ति #35 में देखा जा सकता है, जहां दो अप्रत्यक्ष एजेंट एक-दूसरे के साथ पूर्ण बहुरूपी संगीत कार्यक्रम में काम करते हुए दो सह-संस्करण कॉल प्रदान करने के लिए मिलकर काम कर रहे हैं। `विज़िट' फ़ीचर के `ए_ऑब्जेक्ट' में एक `एनकाउंटर_एजेंट' होता है जिसे 'अल_यूनिवर्स_ऑब्जेक्ट' से आने वाले `सेंसर_डेटा_एजेंट' के सेंसर डेटा के साथ बुलाया जाता है।
डबल-डिस्पैच को पंक्ति #35 में देखा जा सकता है, जहां दो अप्रत्यक्ष एजेंट एक-दूसरे के साथ पूर्ण बहुरूपी संगीत फंक्शन में काम करते हुए दो सह-संस्करण कॉल प्रदान करने के लिए मिलकर काम कर रहे हैं। `विज़िट' फ़ीचर के `a_ऑब्जेक्ट' में `एनकाउंटर_एजेंट' होता है जिसे 'अल_यूनिवर्स_ऑब्जेक्ट' से आने वाले `सेंसर_डेटा_एजेंट' के सेंसर डेटा के साथ बुलाया जाता है।
 
इस विशेष उदाहरण का अन्य दिलचस्प हिस्सा SPACE_OBJECT वर्ग और इसकी 'मुठभेड़' सुविधा है:
इस विशेष उदाहरण का अन्य दिलचस्प हिस्सा SPACE_OBJECT वर्ग और इसकी 'मुठभेड़' सुविधा है:


=== आगंतुक कार्रवाई ===
=== विजिटर गतिविधि ===
SPACE_OBJECT की एकमात्र निर्यातित विशेषताएँ मुठभेड़ और सेंसर डेटा के लिए एजेंट हैं, साथ ही एक नई स्थिति निर्धारित करने की क्षमता भी हैं। जैसे ही एक वस्तु (अंतरिक्ष यान) ब्रह्मांड में प्रत्येक वस्तु का दौरा करती है, सेंसर डेटा एकत्र किया जाता है और उसके मुठभेड़ एजेंट में आने वाली वस्तु को भेज दिया जाता है। वहां, Sensor_data_agent से सेंसर डेटा (अर्थात्- Sensor_data_agent क्वेरी द्वारा लौटाए गए सेंसर_डेटा TUPLE के डेटा तत्व आइटम) का मूल्यांकन वर्तमान ऑब्जेक्ट के विरुद्ध किया जाता है और उस मूल्यांकन के आधार पर कार्रवाई की जाती है (नीचे SPACE_OBJECT में 'एनकाउंटर' देखें)
SPACE_OBJECT की एकमात्र निर्यातित विशेषताएँ सामना और सेंसर डेटा के लिए एजेंट हैं, साथ ही नई स्थिति निर्धारित करने की क्षमता भी हैं। जैसे ही वस्तु (अंतरिक्ष यान) ब्रह्मांड में प्रत्येक वस्तु का निरीक्षण करती है, सेंसर डेटा एकत्र किया जाता है और उसके मुठभेड़ एजेंट में आने वाली वस्तु को भेज दिया जाता है। वहां, Sensor_data_agent से सेंसर डेटा (अर्थात्- Sensor_data_agent क्वेरी द्वारा लौटाए गए सेंसर_डेटा TUPLE के डेटा तत्व आइटम) का मूल्यांकन वर्तमान ऑब्जेक्ट के विरुद्ध किया जाता है और उस मूल्यांकन के आधार पर कार्रवाई की जाती है (नीचे SPACE_OBJECT में 'एनकाउंटर' देखें।)
 
अन्य सभी डेटा को {NONE} में निर्यात किया जाता है। यह प्राइवेट के C, C++ और Java स्कोप के समान है। गैर-निर्यातित सुविधाओं के रूप में, डेटा और रूटीन का उपयोग प्रत्येक SPACE_OBJECT द्वारा केवल आंतरिक रूप से किया जाता है।
अन्य सभी डेटा को {NONE} में निर्यात किया जाता है। यह प्राइवेट के C, C++ और Java स्कोप के समान है। गैर-निर्यातित सुविधाओं के रूप में, डेटा और रूटीन का उपयोग प्रत्येक SPACE_OBJECT द्वारा केवल आंतरिक रूप से किया जाता है।
अंत में, ध्यान दें कि 'प्रिंट' के लिए एनकाउंटर कॉल में SPACE_OBJECT के संभावित वंशज वर्गों के बारे में विशिष्ट जानकारी शामिल नहीं है! विरासत में इस स्तर पर पाई जाने वाली एकमात्र चीज़ सामान्य संबंधपरक पहलू हैं जो पूरी तरह से सामान्य SPACE_OBJECT की विशेषताओं और दिनचर्या से ज्ञात की जा सकने वाली बातों पर आधारित हैं। तथ्य यह है कि स्टार जहाजों, अंतरिक्ष स्टेशनों और क्षुद्रग्रहों के बारे में हम जो जानते हैं या कल्पना करते हैं, उसके आधार पर 'प्रिंट' का आउटपुट हमारे लिए मनुष्य के रूप में समझ में आता है, यह केवल तार्किक योजना या संयोग है। SPACE_OBJECT को उसके वंशजों के किसी विशिष्ट ज्ञान के साथ प्रोग्राम नहीं किया गया है।
 
अंत में, ध्यान दें कि 'प्रिंट' के लिए एनकाउंटर कॉल में SPACE_OBJECT के संभावित वंशज वर्गों के बारे में विशिष्ट जानकारी सम्मिलित नहीं है! विरासत में इस स्तर पर पाई जाने वाली एकमात्र चीज़ सामान्य संबंधपरक पहलू हैं जो पूरी तरह से सामान्य SPACE_OBJECT की विशेषताओं और दिनचर्या से ज्ञात की जा सकने वाली बातों पर आधारित हैं। तथ्य यह है कि स्टार जहाजों, अंतरिक्ष स्टेशनों और क्षुद्रग्रहों के बारे में हम जो जानते हैं या कल्पना करते हैं, उसके आधार पर 'प्रिंट' का आउटपुट हमारे लिए मनुष्य के रूप में समझ में आता है, यह केवल तार्किक योजना या संयोग है। SPACE_OBJECT को उसके डिसेंडेन्ट्स के किसी विशिष्ट ज्ञान के साथ प्रोग्राम नहीं किया गया है।
<syntaxhighlight lang="eiffel" line>
<syntaxhighlight lang="eiffel" line>
deferred class
deferred class
Line 469: Line 477:
SPACESTATION
SPACESTATION
</syntaxhighlight>
</syntaxhighlight>
हमारे उदाहरण में, क्षुद्रग्रह वर्ग का उपयोग 'दुष्ट' वस्तुओं के लिए किया जाता है, दो सितारा जहाजों के लिए स्पेसशिप और डीप स्पेस नाइन के लिए स्पेसस्टेशन का उपयोग किया जाता है। प्रत्येक वर्ग में, एकमात्र विशेषज्ञता 'प्रकार' सुविधा और वस्तु के कुछ गुणों की सेटिंग है। रचना क्रम में 'नाम' के साथ-साथ 'पद' भी दिया जाता है।
हमारे उदाहरण में, क्षुद्रग्रह वर्ग का उपयोग 'रोग्यु' वस्तुओं के लिए किया जाता है, दो सितारा जहाजों के लिए स्पेसशिप और डीप स्पेस नाइन के लिए स्पेसस्टेशन का उपयोग किया जाता है। प्रत्येक वर्ग में, एकमात्र विशेषज्ञता 'टाइप' सुविधा और वस्तु के कुछ गुणों की सेटिंग है। रचना क्रम में 'नाम' के साथ-साथ 'पद' भी दिया जाता है।
 
उदाहरण के लिए: नीचे स्पेसशिप उदाहरण है।
उदाहरण के लिए: नीचे स्पेसशिप उदाहरण है।
<syntaxhighlight lang="eiffel" line>
<syntaxhighlight lang="eiffel" line>
Line 489: Line 498:
end
end
</syntaxhighlight>
</syntaxhighlight>
तो, हमारे ब्रह्मांड में कोई भी अंतरिक्ष यान डॉक-सक्षम, मानवयुक्त और गतिशीलता योग्य है। अन्य वस्तुएं, जैसे क्षुद्रग्रह, इनमें से कोई भी चीज़ नहीं हैं। दूसरी ओर, एक स्पेसस्टेशन डॉक-सक्षम और मानवयुक्त दोनों है, लेकिन गतिशीलता योग्य नहीं है। इस प्रकार, जब एक वस्तु का दूसरे के साथ सामना होता है, तो यह पहले यह देखने के लिए जांच करता है कि क्या स्थिति उन्हें एक-दूसरे के आसपास रखती है और यदि वे हैं, तो वस्तुएं अपने मूल गुणों के आधार पर बातचीत करती हैं।
तो, हमारे स्पेस में कोई भी अंतरिक्ष यान डॉक-सक्षम, मानवयुक्त और गतिशीलता योग्य है। अन्य वस्तुएं, जैसे क्षुद्रग्रह, इनमें से कोई भी चीज़ नहीं हैं। दूसरी ओर स्पेसस्टेशन डॉक-सक्षम और मानवयुक्त दोनों है, लेकिन गतिशीलता योग्य नहीं है। इस टाइप, जब वस्तु का दूसरे के साथ सामना होता है, तो यह पहले यह देखने के लिए जांच करता है कि क्या स्थिति उन्हें एक-दूसरे के आसपास रखती है और यदि वे हैं, तो वस्तुएं अपने मूल गुणों के आधार पर वार्तालाप करती हैं।
ध्यान दें कि समान प्रकार और नाम वाली वस्तुओं को एक ही वस्तु माना जाता है, इसलिए तार्किक रूप से बातचीत की अनुमति नहीं है।
 
ध्यान दें कि समान टाइप और नाम वाली वस्तुओं को एक ही वस्तु माना जाता है, इसलिए तार्किक रूप से वार्तालाप की अनुमति नहीं है।


=== एफिल उदाहरण निष्कर्ष ===
=== एफिल उदाहरण निष्कर्ष ===
डबल-डिस्पैच के संबंध में, एफिल डिजाइनर और प्रोग्रामर को क्लास रूटीन को एजेंट बनाकर और फिर डायरेक्ट ऑब्जेक्ट फीचर कॉल करने के बजाय उन एजेंटों को पास करके उनकी कक्षाओं से क्लास रूटीन को अलग करके प्रत्यक्ष ऑब्जेक्ट-टू-ऑब्जेक्ट ज्ञान के स्तर को हटाने की अनुमति देता है। एजेंटों के पास विशिष्ट हस्ताक्षर और संभावित परिणाम (प्रश्नों के मामले में) भी होते हैं, जिससे वे विशिष्ट वस्तु विवरण छोड़े बिना आदर्श स्थैतिक प्रकार की जांच करने वाले वाहन बन जाते हैं। एजेंट पूरी तरह से बहुरूपी होते हैं, इसलिए परिणामी कोड में केवल अपना स्थानीय कार्य पूरा करने के लिए आवश्यक विशिष्ट ज्ञान होता है। अन्यथा, कई सह-संस्करण वस्तुओं के आसपास विशिष्ट आंतरिक वर्ग सुविधा ज्ञान फैलने से कोई रखरखाव बोझ नहीं बढ़ता है। एजेंटों का उपयोग और यांत्रिकी यह सुनिश्चित करती है।
डबल-डिस्पैच के संबंध में, एफिल डिजाइनर और प्रोग्रामर को क्लास रूटीन को एजेंट बनाकर और फिर डायरेक्ट ऑब्जेक्ट फीचर कॉल करने के अतिरिक्त उन एजेंटों को पास करके उनकी कक्षाओं से क्लास रूटीन को अलग करके प्रत्यक्ष ऑब्जेक्ट-टू-ऑब्जेक्ट ज्ञान के स्तर को हटाने की अनुमति देता है। एजेंटों के पास विशिष्ट हस्ताक्षर और संभावित परिणाम (प्रश्नों के स्थितियों में) भी होते हैं, जिससे वे विशिष्ट वस्तु विवरण छोड़े बिना आदर्श स्थैतिक टाइप की जांच करने वाले वाहन बन जाते हैं। एजेंट पूरी तरह से बहुरूपी होते हैं, इसलिए परिणामी कोड में केवल अपना स्थानीय कार्य पूरा करने के लिए आवश्यक विशिष्ट ज्ञान होता है। अन्यथा, कई सह-संस्करण वस्तुओं के आसपास विशिष्ट आंतरिक वर्ग सुविधा ज्ञान फैलने से कोई देखभाल का बोझ नहीं बढ़ता है। एजेंटों का उपयोग और यांत्रिकी यह सुनिश्चित करती है।
एजेंटों के उपयोग का एक संभावित नकारात्मक पक्ष यह है कि एक एजेंट अपने प्रत्यक्ष कॉल समकक्ष की तुलना में कम्प्यूटेशनल रूप से अधिक महंगा है। इसे ध्यान में रखते हुए, किसी को कभी भी डबल-डिस्पैच में एजेंटों के उपयोग और विज़िटर पैटर्न में उनके आवेदन का अनुमान नहीं लगाना चाहिए। यदि कोई स्पष्ट रूप से वर्ग प्रकारों के डोमेन के रूप में एक डिज़ाइन सीमा देख सकता है जो सह-संस्करण इंटरैक्शन में शामिल होगा, तो कम्प्यूटेशनल व्यय के संदर्भ में एक सीधी कॉल अधिक कुशल समाधान है। हालाँकि, यदि भाग लेने वाले प्रकारों के वर्ग डोमेन के बढ़ने या काफी भिन्न होने की उम्मीद है, तो एजेंट डबल-डिस्पैच पैटर्न में रखरखाव के बोझ को कम करने के लिए एक उत्कृष्ट समाधान प्रस्तुत करते हैं।
 
एजेंटों के उपयोग का संभावित नकारात्मक पक्ष यह है कि एजेंट अपने प्रत्यक्ष कॉल समकक्ष की तुलना में कम्प्यूटेशनल रूप से अधिक बहुमूल्य है। इसे ध्यान में रखते हुए, किसी को कभी भी डबल-डिस्पैच में एजेंटों के उपयोग और विज़िटर पैटर्न में उनके आवेदन का अनुमान नहीं लगाना चाहिए। यदि कोई स्पष्ट रूप से वर्ग टाइपों के डोमेन के रूप में डिज़ाइन सीमा देख सकता है जो सह-संस्करण इंटरैक्शन में सम्मिलित होगा, तो कम्प्यूटेशनल व्यय के संदर्भ में सीधी कॉल अधिक कुशल समाधान है। चूँकि, यदि भाग लेने वाले टाइपों के वर्ग डोमेन के बढ़ने या बहुत भिन्न होने की आशा है, तो एजेंट डबल-डिस्पैच पैटर्न में देखभाल के बोझ को कम करने के लिए उत्कृष्ट समाधान प्रस्तुत करते हैं।


==यह भी देखें==
==यह भी देखें==
*विज़िटर पैटर्न
*विज़िटर पैटर्न
* एकाधिक प्रेषण
* मल्टीप्ल डिस्पैच
* हैश फ़ंक्शन#ट्रिविअल हैश फ़ंक्शन
* ट्रिविअल हैश फंक्शन
* [[ आभासी तालिका ]]
* [[ आभासी तालिका ]]


==संदर्भ==
==संदर्भ==
{{Reflist}}
{{Reflist}}
{{Refimprove|article|date=August 2008}}
{{DEFAULTSORT:Double Dispatch}}
 
{{DEFAULTSORT:Double Dispatch}}[[Category: सॉफ़्टवेयर डिज़ाइन पैटर्न]] [[Category: विधि (कंप्यूटर प्रोग्रामिंग)]] [[Category: उदाहरण C++ कोड वाले लेख]]
 
 


[[Category: Machine Translated Page]]
[[Category:Created On 25/07/2023|Double Dispatch]]
[[Category:Created On 25/07/2023]]
[[Category:Machine Translated Page|Double Dispatch]]
[[Category:Pages with script errors|Double Dispatch]]
[[Category:Pages with syntax highlighting errors]]
[[Category:Templates Vigyan Ready|Double Dispatch]]
[[Category:उदाहरण C++ कोड वाले लेख|Double Dispatch]]
[[Category:विधि (कंप्यूटर प्रोग्रामिंग)|Double Dispatch]]
[[Category:सॉफ़्टवेयर डिज़ाइन पैटर्न|Double Dispatch]]

Latest revision as of 11:31, 11 August 2023

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

डैन इंगल्स ने सबसे पहले स्मॉलटॉक में डबल डिस्पैचिंग का उपयोग करने का विधि बताया था, इसे मल्टीप्ल बहुरूपता कहा गया था।[1]


अवलोकन

सामान्य समस्या यह है कि किसी मैसेज को न केवल प्राप्तकर्ता पर किन्तु तर्कों पर भी निर्भर करते हुए विभिन्न विधियों से कैसे भेजा जाए।

उस अंत तक, सीएलओएस जैसी प्रणालियाँ मल्टीप्ल डिस्पैच प्रयुक्त करती हैं। डबल डिस्पैच एक और समाधान है जो धीरे-धीरे उन प्रणालियों पर बहुरूपता को कम करता है जो मल्टीपल डिस्पैच का समर्थन नहीं करते हैं।

स्थितियों का प्रयोग करें

डबल डिस्पैच उन स्थितियों में उपयोगी है जहां गणना का विकल्प उसके तर्कों के रनटाइम टाइपों पर निर्भर करता है। उदाहरण के लिए प्रोग्रामर निम्नलिखित स्थितियों में डबल डिस्पैच का उपयोग कर सकता है:

  • वस्तुओं के मिश्रित सेट को क्रमबद्ध करना: एल्गोरिदम के लिए आवश्यक है कि वस्तुओं की सूची को कुछ विहित क्रम में क्रमबद्ध किया जाए। यह निर्णय लेने के लिए कि क्या तत्व दूसरे तत्व से पहले आता है, दोनों टाइप के ज्ञान और संभवतः क्षेत्रों के कुछ सबसेट की आवश्यकता होती है।
  • अनुकूली कोलिजन एल्गोरिदम के लिए सामान्यतः आवश्यकता होती है कि विभिन्न वस्तुओं के बीच कोलिजन को अलग-अलग विधियों से नियंत्रित किया जाए। विशिष्ट उदाहरण खेल के स्थिति में है जहां अंतरिक्ष यान और क्षुद्रग्रह के बीच कोलिजन की गणना अंतरिक्ष यान और अंतरिक्ष स्टेशन के बीच कोलिजन से अलग विधियों से की जाती है।[2]
  • पेंटिंग एल्गोरिदम जिन्हें ओवरलैपिंग स्प्राइट (कंप्यूटर ग्राफिक्स) के प्रतिच्छेदन बिंदुओं को अलग विधियों से प्रस्तुत करने की आवश्यकता होती है।
  • कार्मिक प्रबंधन प्रणालियाँ विभिन्न कर्मियों को विभिन्न टाइप की नौकरियाँ भेज सकती हैं। A schedule एल्गोरिदम जो व्यक्ति को अकाउंटेंट के रूप में टाइप की गई वस्तु और इंजीनियरिंग के रूप में टाइप की गई नौकरी की वस्तु देता है, उस नौकरी के लिए उस व्यक्ति की शेड्यूलिंग को अस्वीकार कर देता है।
  • इवेंट हैंडलिंग प्रणाली जो सही इवेंट हैंडलिंग रूटीन को कॉल करने के लिए इवेंट टाइप और रिसेप्टर ऑब्जेक्ट के टाइप दोनों का उपयोग करते हैं।
  • ताला और कुंजी प्रणालियाँ जहाँ कई टाइप के ताले और कई टाइप की कीस होती हैं और प्रत्येक टाइप की कुंजी कई टाइप के ताले खोलती है। आपको न केवल इसमें सम्मिलित वस्तुओं के टाइपों को जानने की आवश्यकता है, बल्कि किसी विशेष कुंजी के बारे में जानकारी का सबसेट जो यह देखने के लिए प्रासंगिक है कि क्या कोई विशेष कुंजी किसी विशेष लॉक को खोलती है, विभिन्न लॉक टाइपों के बीच भिन्न होती है।

सामान्य मुहावरा

सामान्य मुहावरा, जैसा कि ऊपर प्रस्तुत उदाहरणों में है, यह है कि उपयुक्त एल्गोरिदम का चयन रनटाइम पर कॉल के तर्क टाइपों पर आधारित होता है। इसलिए कॉल सभी सामान्य अतिरिक्त प्रदर्शन लागतों के अधीन है जो कॉल के गतिशील रिज़ॉल्यूशन से जुड़ी हैं, सामान्यतः केवल एकल विधि डिस्पैच का समर्थन करने वाली लैंग्वेज की तुलना में अधिक। उदाहरण के लिए, C++ में, डायनेमिक फंक्शन कॉल को सामान्यतः एकल ऑफसेट (कंप्यूटर विज्ञान) गणना द्वारा हल किया जाता है - जो संभव है क्योंकि कंपाइलर ऑब्जेक्ट की वर्चुअल विधि तालिका में फंक्शन का स्थान जानता है और इसलिए ऑफसेट की सांख्यिकीय गणना कर सकता है। डबल डिस्पैच का समर्थन करने वाली लैंग्वेज में, यह थोड़ा अधिक बहुमूल्य है, क्योंकि कंपाइलर को रनटाइम पर विधि तालिका में विधि के ऑफसेट की गणना करने के लिए कोड उत्पन्न करना होगा, जिससे समग्र निर्देश पथ की लंबाई बढ़ जाएगी (ऐसी राशि जो फंक्शन में कॉल की कुल संख्या से अधिक नहीं होने की संभावना है, जो बहुत महत्वपूर्ण नहीं हो सकती है।)

रूबी में उदाहरण

सामान्य उपयोग की स्थितियां डिस्प्ले पोर्ट पर ऑब्जेक्ट प्रदर्शित करना है जो स्क्रीन या प्रिंटर हो सकता है, या पूरी तरह से कुछ और जो अभी तक उपस्थित नहीं है। यह उन विभिन्न मीडिया से निपटने का अनुभवहीन कार्यान्वयन है।

class Rectangle
  def display_on(port)
    # selects the right code based on the object class
    case port
      when DisplayPort
        # code for displaying on DisplayPort
      when PrinterPort
        # code for displaying on PrinterPort
      when RemotePort
        # code for displaying on RemotePort
    end
  end
end

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

अधिक स्वच्छ और अधिक रख-रखाव योग्य समाधान यह है कि इस बार माध्यम पर वस्तु को प्रदर्शित करने के लिए सही विधि का चयन करने के लिए दूसरा डिस्पैच किया जाए:

class Rectangle
  def display_on(port)
    # second dispatch
    port.display_rectangle(self)
  end
end

class Oval
  def display_on(port)
    # second dispatch
    port.display_oval(self)
  end
end

class DisplayPort
  def display_rectangle(object)
    # code for displaying a rectangle on a DisplayPort
  end
  def display_oval(object)
    # code for displaying an oval on a DisplayPort
  end
  # ...
end

class PrinterPort
  def display_rectangle(object)
    # code for displaying a rectangle on a PrinterPort
  end
  def display_oval(object)
    # code for displaying an oval on a PrinterPort
  end
  # ...
end


C++ में डबल डिस्पैच

पहली दृष्टी में, डबल डिस्पैच फंक्शन ओवरलोडिंग का स्वाभाविक परिणाम प्रतीत होता है। फंक्शन ओवरलोडिंग कॉल किए गए फंक्शन को तर्क के टाइप पर निर्भर करने की अनुमति देता है। चूँकि, फंक्शन ओवरलोडिंग, नाम मंगलिंग का उपयोग करके संकलन समय पर किया जाता है, जहां फंक्शन का आंतरिक नाम तर्क के टाइप को एन्कोड करता है। उदाहरण के लिए फंक्शन foo(int) को आंतरिक रूप से __foo_i बुलाया जा सकता है और फंक्शन foo(double) को __foo_d बुलाया जा सकता है। इस टाइप, कोई नाम कोलिजन नहीं है, और कोई वर्चुअल टेबल लुकअप नहीं है। इसके विपरीत, डायनेमिक डिस्पैच कॉलिंग ऑब्जेक्ट के टाइप पर आधारित होता है, जिसका अर्थ है कि यह फंक्शन ओवरलोडिंग के अतिरिक्त आभासी कार्य (ओवरराइडिंग) का उपयोग करता है, और इसके परिणामस्वरूप व्यवहार्य लुकअप होता है। किसी गेम में कोलिजन के C++ में लिखे गए निम्नलिखित उदाहरण पर विचार करें:

class SpaceShip {};
class ApolloSpacecraft : public SpaceShip {};

class Asteroid {
public:
  virtual void CollideWith(SpaceShip&) {
    std::cout << "Asteroid hit a SpaceShip\n";
  }
  virtual void CollideWith(ApolloSpacecraft&) {
    std::cout << "Asteroid hit an ApolloSpacecraft\n";
  }
};

class ExplodingAsteroid : public Asteroid {
public:
  void CollideWith(SpaceShip&) override {
    std::cout << "ExplodingAsteroid hit a SpaceShip\n";
  }
  void CollideWith(ApolloSpacecraft&) override {
    std::cout << "ExplodingAsteroid hit an ApolloSpacecraft\n";
  }
};

यदि आपके पास है:

Asteroid theAsteroid;
SpaceShip theSpaceShip;
ApolloSpacecraft theApolloSpacecraft;

फिर, फंक्शन ओवरलोडिंग के कारण,

theAsteroid.CollideWith(theSpaceShip); 
theAsteroid.CollideWith(theApolloSpacecraft);

क्रमशः Asteroid hit a SpaceShip और Asteroid hit an ApolloSpacecraft , बिना किसी गतिशील डिस्पैच का उपयोग किए प्रिंट करेगा। आगे:

ExplodingAsteroid theExplodingAsteroid;
theExplodingAsteroid.CollideWith(theSpaceShip); 
theExplodingAsteroid.CollideWith(theApolloSpacecraft);

ExplodingAsteroid hit a SpaceShip और ExplodingAsteroid hit an ApolloSpacecraft फिर से गतिशील डिस्पैच के बिना क्रमशः प्रिंट हो जायेगा।

Asteroid के संदर्भ में, गतिशील डिस्पैच का उपयोग किया जाता है, और यह कोड:

Asteroid& theAsteroidReference = theExplodingAsteroid;
theAsteroidReference.CollideWith(theSpaceShip); 
theAsteroidReference.CollideWith(theApolloSpacecraft);

प्रिंट ExplodingAsteroid hit a SpaceShip और ExplodingAsteroid hit an ApolloSpacecraft, फिर से जैसी कि आशा थी। चूँकि, निम्नलिखित कोड इच्छानुसार काम नहीं करता है:

SpaceShip& theSpaceShipReference = theApolloSpacecraft;
theAsteroid.CollideWith(theSpaceShipReference);
theAsteroidReference.CollideWith(theSpaceShipReference);

वांछित व्यवहार इन कॉलों को उस फंक्शन से बांधना है, जो theApolloSpacecraft इसके तर्क के रूप में लेता है, क्योंकि यह चर का तात्कालिक टाइप है, जिसका अर्थ है कि अपेक्षित आउटपुट Asteroid hit an ApolloSpacecraft और ExplodingAsteroid hit an ApolloSpacecraft होगा। चूँकि, आउटपुट वास्तव में Asteroid hit a SpaceShip और ExplodingAsteroid hit a SpaceShip है। समस्या यह है कि, जबकि वर्चुअल फंक्शन C++ में गतिशील रूप से भेजे जाते हैं, तो फंक्शन ओवरलोडिंग स्थिर रूप से की जाती है।

ऊपर वर्णित समस्या को दोहरे डिस्पैच का अनुकरण करके हल किया जा सकता है, उदाहरण के लिए विजिटर पैटर्न का उपयोग करके। मान लीजिए कि उपस्थिता कोड को बढ़ाया गया है जिससे दोनों SpaceShip और ApolloSpacecraft फंक्शन दिया गया है

virtual void CollideWith(Asteroid& inAsteroid) {
  inAsteroid.CollideWith(*this);
}

फिर, जबकि पिछला उदाहरण अभी भी सही ढंग से काम नहीं करता है, कॉल को फिर से फ्रेम करना जिससे अंतरिक्ष यान एजेंट हो, हमें वांछित व्यवहार देता है:

SpaceShip& theSpaceShipReference = theApolloSpacecraft;
Asteroid& theAsteroidReference = theExplodingAsteroid;
theSpaceShipReference.CollideWith(theAsteroid);
theSpaceShipReference.CollideWith(theAsteroidReference);

यह Asteroid hit an ApolloSpacecraft और ExplodingAsteroid hit an ApolloSpacecraft प्रिंट कर लेता है, आशा के अनुसार कुंजी theSpaceShipReference.CollideWith(theAsteroidReference); रन टाइम पर निम्न कार्य करता है:

  1. theSpaceShipReference संदर्भ है, इसलिए C++ vtable में सही विधि ढूंढता है। इस स्थितियों में, यह ApolloSpacecraft::CollideWith(Asteroid&) कॉल करेगा।
  2. अंदर ApolloSpacecraft::CollideWith(Asteroid&), inAsteroid संदर्भ है, इसलिए inAsteroid.CollideWith(*this) इसके परिणामस्वरूप एक और वेटेबल लुकअप होगा। इस स्थितियों में, inAsteroid का संदर्भ ExplodingAsteroid है इसलिए ExplodingAsteroid::CollideWith(ApolloSpacecraft&) बुलाया जाएगा।

C# में डबल डिस्पैच

(प्रोग्रामिंग लैंग्वेज) C# में, किसी तर्क को स्वीकार करते हुए इंस्टेंस विधि को कॉल करते समय, विज़िटर पैटर्न को नियोजित किए बिना मल्टीप्ल डिस्पैच प्राप्त किया जा सकता है। यह तर्क को गतिशील बनाते हुए पारंपरिक बहुरूपता का उपयोग करके किया जाता है।[3] रन-टाइम बाइंडर रन-टाइम पर उचित विधि ओवरलोड का चयन करेगा। यह निर्णय ऑब्जेक्ट इंस्टेंस के रन-टाइम टाइप (बहुरूपता) के साथ-साथ तर्क के रन-टाइम टाइप को भी ध्यान में रखेगा।

एफिल में डबल डिस्पैच

एफिल (प्रोग्रामिंग लैंग्वेज) प्रोग्रामिंग लैंग्वेज एजेंटों की अवधारणा को डबल-डिस्पैच समस्या पर सहन करने के लिए ला सकती है। नीचे दिया गया उदाहरण एजेंट लैंग्वेज निर्माण को डबल-डिस्पैच समस्या पर प्रयुक्त करता है।

आकृति के विभिन्न रूपों और सतह को चित्रित करने वाले समस्या डोमेन पर विचार करें, जिस पर आकृति बनाई जाए। SHAPE और SURFACE दोनों अपने आप में `draw' नामक फंक्शन के बारे में जानते हैं, लेकिन दूसरे में नहीं हम चाहते हैं कि दो टाइप की वस्तुएं विज़िटर पैटर्न का उपयोग करके डबल-डिस्पैच में एक-दूसरे के साथ सह-भिन्न रूप से वार्तालाप करें। चुनौती बहुरूपी सतह को अपने ऊपर बहुरूपी आकार बनाने के लिए प्राप्त करना है।

आउटपुट

नीचे दिया गया आउटपुट उदाहरण दो SURFACE विज़िटर ऑब्जेक्ट्स के परिणाम दिखाता है जिन्हें पॉलीमॉर्फिक SHAPE ऑब्जेक्ट्स की सूची में पॉलीमॉर्फिक रूप से पारित किया गया है। विज़िटर कोड पैटर्न केवल सामान्य रूप से SHAPE और SURFACE के बारे में जानता है, किसी विशिष्ट टाइप के बारे में नहीं। इसके अतिरिक्त, कोड इन दो स्थगित वर्गों और उनके डिसेंडेन्ट्स के बीच अत्यधिक लचीले सह-संस्करण संबंध प्राप्त करने के लिए रन-टाइम बहुरूपता और एजेंटों के यांत्रिकी पर निर्भर करता है।

draw a red POLYGON on ETCHASKETCH
draw a red POLYGON on GRAFFITI_WALL
draw a grey RECTANGLE on ETCHASKETCH
draw a grey RECTANGLE on GRAFFITI_WALL
draw a green QUADRILATERAL on ETCHASKETCH
draw a green QUADRILATERAL on GRAFFITI_WALL
draw a blue PARALLELOGRAM on ETCHASKETCH
draw a blue PARALLELOGRAM on GRAFFITI_WALL
draw a yellow POLYGON on ETCHASKETCH
draw a yellow POLYGON on GRAFFITI_WALL
draw a purple RECTANGLE on ETCHASKETCH
draw a purple RECTANGLE on GRAFFITI_WALL


सेटअप

SHAPE या SURFACE को देखने से पहले, हमें अपने डबल-डिस्पैच के उच्च स्तरीय डिकौपल्ड उपयोग की जांच करने की आवश्यकता है।

विज़िटर पैटर्न

विज़िटर पैटर्न विज़िटर ऑब्जेक्ट के माध्यम से डेटा संरचना के तत्वों (उदाहरण के लिए सूची, पेड़ और इसी तरह) पर जाकर बहुरूपी रूप से काम करता है, विज़िट की गई लक्ष्य संरचना में बहुरूपी तत्व ऑब्जेक्ट के विरुद्ध कुछ कार्रवाई (कॉल या एजेंट) प्रयुक्त करता है।

नीचे दिए गए हमारे उदाहरण में, हम बहुरूपी SHAPE वस्तुओं की सूची बनाते हैं, उनमें से प्रत्येक को बहुरूपी सतह के साथ देखते हैं, और सतह पर आकृति बनाने के लिए कहते हैं।

make
			-- Print shapes on surfaces.
		local
			l_shapes: ARRAYED_LIST [SHAPE]
			l_surfaces: ARRAYED_LIST [SURFACE]
		do
			create l_shapes.make (6)
			l_shapes.extend (create {POLYGON}.make_with_color ("red"))
			l_shapes.extend (create {RECTANGLE}.make_with_color ("grey"))
			l_shapes.extend (create {QUADRILATERAL}.make_with_color ("green"))
			l_shapes.extend (create {PARALLELOGRAM}.make_with_color ("blue"))
			l_shapes.extend (create {POLYGON}.make_with_color ("yellow"))
			l_shapes.extend (create {RECTANGLE}.make_with_color ("purple"))

			create l_surfaces.make (2)
			l_surfaces.extend (create {ETCHASKETCH}.make)
			l_surfaces.extend (create {GRAFFITI_WALL}.make)

			across l_shapes as ic_shapes loop
				across l_surfaces as ic_surfaces loop
					ic_surfaces.item.drawing_agent (ic_shapes.item.drawing_data_agent)
				end
			end
		end

हम SHAPE और SURFACE वस्तुओं का संग्रह बनाकर प्रारंभ करते हैं। फिर हम सूचियों (SHAPE) में से एक पर पुनरावृत्ति करते हैं, जिससे दूसरे (SURFACE) के तत्वों को बारी-बारी से उनमें से प्रत्येक पर जाने की अनुमति मिलती है। उपरोक्त उदाहरण कोड में, SURFACE ऑब्जेक्ट SHAPE ऑब्जेक्ट पर जा रहे हैं।

कोड {SURFACE} पर बहुरूपी कॉल करता है। Drawing_agent के माध्यम से अप्रत्यक्ष रूप से ड्रा करें, जो डबल-डिस्पैच पैटर्न की पहली कॉल (डिस्पैच) है। यह अप्रत्यक्ष और बहुरूपी एजेंट (`drawing_data_agent') पास करता है, जिससे हमारे विज़िटर कोड को केवल दो चीजों के बारे में जानने की अनुमति मिलती है:

  • सतह का ड्राइंग एजेंट क्या है (उदाहरण के लिए al_surface.drawing_agent on line #21)?
  • आकृति का ड्राइंग डेटा एजेंट क्या है (उदाहरण के लिए al_shape.drawing_data_agent on line #21)?

चूँकि SURFACE और SHAPE दोनों ही अपने स्वयं के एजेंटों को परिभाषित करते हैं, इसलिए हमारे विज़िटर कोड को यह जानने से मुक्ति मिल जाती है कि बहुरूपी या अन्यथा, करने के लिए उपयुक्त कॉल क्या है। इनडायरेक्शन और डिकॉउलिंग का यह स्तर C, C++ और जावा जैसी अन्य सामान्य लैंग्वेजओं में किसी टाइप के रिफ्लेक्सन (कंप्यूटर विज्ञान) या हस्ताक्षर मिलान के साथ फीचर ओवरलोडिंग को छोड़कर सरलता से प्राप्त नहीं किया जा सकता है।

सतह

बहुरूपी कॉल के अन्दर {SURFACE}.draw एजेंट के लिए कॉल है, जो डबल-डिस्पैच पैटर्न में दूसरी बहुरूपी कॉल या डिस्पैच बन जाता है।

	deferred class
		SURFACE
	
	feature {NONE} -- Initialization
	
		make
				-- Initialize Current.
			do
				drawing_agent := agent draw
			end
	
	feature -- Access

		drawing_agent: PROCEDURE [ANY, TUPLE [STRING, STRING]]
				-- Drawing agent of Current.
	
	feature {NONE} -- Implementation
	
		draw (a_data_agent: FUNCTION [ANY, TUPLE, TUPLE [name, color: STRING]])
				-- Draw `a_shape' on Current.
			local
				l_result: TUPLE [name, color: STRING]
			do
				l_result := a_data_agent (Void)
				print ("draw a " + l_result.color + " " + l_result.name + " on " + type + "%N")
			end
	
		type: STRING
				-- Type name of Current.
			deferred end
	
	end

पंक्ति #19 में एजेंट तर्क और पंक्ति #24 में कॉल दोनों बहुरूपी और वियुग्मित हैं। एजेंट को अलग कर दिया गया है क्योंकि {SURFACE}.draw फीचर को पता नहीं है कि `a_data_agent' किस वर्ग पर आधारित है। यह बताने का कोई विधि नहीं है कि ऑपरेशन एजेंट किस वर्ग से लिया गया था, इसलिए इसे SHAPE या उसके डिसेंडेन्ट्स में से किसी एक से आना आवश्यक नहीं है। यह अन्य लैंग्वेजओं की एकल विरासत, गतिशील और बहुरूपी बंधन पर एफिल एजेंटों का विशिष्ट लाभ है।

रन-टाइम पर एजेंट गतिशील रूप से बहुरूपी होता है क्योंकि ऑब्जेक्ट को उसी क्षण बनाया जाता है, जब इसकी आवश्यकता होती है, गतिशील रूप से, जहां उस समय ऑब्जेक्टिफाइड रूटीन का संस्करण निर्धारित किया जाता है। एकमात्र दृढ़ता से बंधा हुआ ज्ञान एजेंट हस्ताक्षर के परिणाम टाइप का है - अर्थात - दो तत्वों के साथ TUPLE नाम दिया गया है। चूँकि, यह विशिष्ट आवश्यकता संलग्न सुविधा की मांग पर आधारित है (उदाहरण के लिए पंक्ति #25, SURFACE की 'draw' सुविधा को पूरा करने के लिए TUPLE के नामित तत्वों का उपयोग करती है), जो आवश्यक है और इसे टाला नहीं गया है (और संभवतया नहीं भी किया जा सकता है)।

अंत में, ध्यान दें कि किसी भी ग्राहक को केवल Drawing_agent सुविधा कैसे निर्यात की जाती है! इसका अर्थ यह है कि विज़िटर पैटर्न कोड (जो इस वर्ग का एकमात्र ग्राहक है) को अपना काम पूरा करने के लिए केवल एजेंट के बारे में जानना होगा (उदाहरण के लिए विज़िट की गई वस्तुओं पर प्रयुक्त सुविधा के रूप में एजेंट का उपयोग करना)।

आकार

SHAPE वर्ग के पास जो कुछ खींचा जाता है उसका आधार होता है (उदाहरण के लिए डेटा खींचना), संभवतया किसी सतह पर, लेकिन ऐसा होना आवश्यक नहीं है। फिर से, एजेंट SHAPE के साथ सह-संस्करण संबंध को यथासंभव विघटित करने के लिए आवश्यक अप्रत्यक्ष और वर्ग अज्ञेयवादी प्रदान करते हैं।

इसके अतिरिक्त, कृपया इस तथ्य पर ध्यान दें कि SHAPE किसी भी ग्राहक को पूरी तरह से निर्यात की गई सुविधा के रूप में केवल 'drawing_data_agent' प्रदान करता है। इसलिए, निर्माण के अतिरिक्त, SHAPE के साथ वार्तालाप करने का एकमात्र विधि 'drawing_data_agent' की सुविधाओं के माध्यम से है, जिसका उपयोग किसी भी क्लाइंट द्वारा SHAPE के लिए अप्रत्यक्ष और बहुरूपी रूप से ड्राइंग डेटा इकट्ठा करने के लिए किया जाता है!

	deferred class
		SHAPE
	
	feature {NONE} -- Initialization
	
		make_with_color (a_color: like color)
				-- Make with `a_color' as `color'.
			do
				color := a_color
				drawing_data_agent := agent drawing_data
			ensure
				color_set: color.same_string (a_color)
			end

	feature -- Access
	
		drawing_data_agent: FUNCTION [ANY, TUPLE, like drawing_data]
				-- Data agent for drawing.
	
	feature {NONE} -- Implementation
	
		drawing_data: TUPLE [name: like name; color: like color]
				-- Data needed for drawing of Current.
			do
				Result := [name, color]
			end
	
		name: STRING
				-- Object name of Current.
			deferred end
	
		color: STRING
				-- Color of Current.

	end


क्लासिक अंतरिक्ष यान उदाहरण

क्लासिक स्पेसशिप उदाहरण की भिन्नता में एक या एक से अधिक स्पेसशिप वस्तुएं रोग्यु क्षुद्रग्रहों और अंतरिक्ष स्टेशनों जैसी अन्य वस्तुओं से भरे ब्रह्मांड में घूम रही हैं। हम जो चाहते हैं वह हमारे काल्पनिक ब्रह्मांड में दो सह-परिवर्ती वस्तुओं के बीच मुठभेड़ों (उदाहरण के लिए संभावित कोलिजन) से निपटने के लिए डबल-डिस्पैच विधि है।

नीचे दिए गए उदाहरण में, हमारे यूएसएस एंटरप्राइज और यूएसएस एक्सेलसियर का आउटपुट भ्रमण होगा:

Starship Enterprise changes position from A-001 to A-002.
Starship Enterprise takes evasive action, avoiding Asteroid `Rogue 1'!
Starship Enterprise changes position from A-002 to A-003.
Starship Enterprise takes evasive action, avoiding Asteroid `Rogue 2'!
Starship Enterprise beams a science team to Starship Excelsior as they pass!
Starship Enterprise changes position from A-003 to A-004.
Starship Excelsior changes position from A-003 to A-005.
Starship Enterprise takes evasive action, avoiding Asteroid `Rogue 3'!
Starship Excelsior is near Space Station Deep Space 9 and is dockable.
Starship Enterprise changes position from A-004 to A-005.
Starship Enterprise beams a science team to Starship Excelsior as they pass!
Starship Enterprise is near Space Station Deep Space 9 and is dockable.


विजिटर

क्लासिक स्पेसशिप उदाहरण के लिए विज़िटर के पास डबल-डिस्पैच सिस्टम भी है।

make
		-- Allow SPACESHIP objects to visit and move about in a universe.
	local
		l_universe: ARRAYED_LIST [SPACE_OBJECT]
		l_enterprise,
		l_excelsior: SPACESHIP
	do
		create l_enterprise.make_with_name ("Enterprise", "A-001")
		create l_excelsior.make_with_name ("Excelsior", "A-003")
		create l_universe.make (0)
		l_universe.force (l_enterprise)
		l_universe.force (create {ASTEROID}.make_with_name ("Rogue 1", "A-002"))
		l_universe.force (create {ASTEROID}.make_with_name ("Rogue 2", "A-003"))
		l_universe.force (l_excelsior)
		l_universe.force (create {ASTEROID}.make_with_name ("Rogue 3", "A-004"))
		l_universe.force (create {SPACESTATION}.make_with_name ("Deep Space 9", "A-005"))
		visit (l_enterprise, l_universe)
		l_enterprise.set_position ("A-002")
		visit (l_enterprise, l_universe)
		l_enterprise.set_position ("A-003")
		visit (l_enterprise, l_universe)
		l_enterprise.set_position ("A-004")
		l_excelsior.set_position ("A-005")
		visit (l_enterprise, l_universe)
		visit (l_excelsior, l_universe)
		l_enterprise.set_position ("A-005")
		visit (l_enterprise, l_universe)
	end
feature {NONE} -- Implementation
visit (a_object: SPACE_OBJECT; a_universe: ARRAYED_LIST [SPACE_OBJECT])
		-- `a_object' visits `a_universe'.
	do
		across a_universe as ic_universe loop
			check attached {SPACE_OBJECT} ic_universe.item as al_universe_object then
				a_object.encounter_agent.call ([al_universe_object.sensor_data_agent])
			end
		end
	end

डबल-डिस्पैच को पंक्ति #35 में देखा जा सकता है, जहां दो अप्रत्यक्ष एजेंट एक-दूसरे के साथ पूर्ण बहुरूपी संगीत फंक्शन में काम करते हुए दो सह-संस्करण कॉल प्रदान करने के लिए मिलकर काम कर रहे हैं। `विज़िट' फ़ीचर के `a_ऑब्जेक्ट' में `एनकाउंटर_एजेंट' होता है जिसे 'अल_यूनिवर्स_ऑब्जेक्ट' से आने वाले `सेंसर_डेटा_एजेंट' के सेंसर डेटा के साथ बुलाया जाता है।

इस विशेष उदाहरण का अन्य दिलचस्प हिस्सा SPACE_OBJECT वर्ग और इसकी 'मुठभेड़' सुविधा है:

विजिटर गतिविधि

SPACE_OBJECT की एकमात्र निर्यातित विशेषताएँ सामना और सेंसर डेटा के लिए एजेंट हैं, साथ ही नई स्थिति निर्धारित करने की क्षमता भी हैं। जैसे ही वस्तु (अंतरिक्ष यान) ब्रह्मांड में प्रत्येक वस्तु का निरीक्षण करती है, सेंसर डेटा एकत्र किया जाता है और उसके मुठभेड़ एजेंट में आने वाली वस्तु को भेज दिया जाता है। वहां, Sensor_data_agent से सेंसर डेटा (अर्थात्- Sensor_data_agent क्वेरी द्वारा लौटाए गए सेंसर_डेटा TUPLE के डेटा तत्व आइटम) का मूल्यांकन वर्तमान ऑब्जेक्ट के विरुद्ध किया जाता है और उस मूल्यांकन के आधार पर कार्रवाई की जाती है (नीचे SPACE_OBJECT में 'एनकाउंटर' देखें।)

अन्य सभी डेटा को {NONE} में निर्यात किया जाता है। यह प्राइवेट के C, C++ और Java स्कोप के समान है। गैर-निर्यातित सुविधाओं के रूप में, डेटा और रूटीन का उपयोग प्रत्येक SPACE_OBJECT द्वारा केवल आंतरिक रूप से किया जाता है।

अंत में, ध्यान दें कि 'प्रिंट' के लिए एनकाउंटर कॉल में SPACE_OBJECT के संभावित वंशज वर्गों के बारे में विशिष्ट जानकारी सम्मिलित नहीं है! विरासत में इस स्तर पर पाई जाने वाली एकमात्र चीज़ सामान्य संबंधपरक पहलू हैं जो पूरी तरह से सामान्य SPACE_OBJECT की विशेषताओं और दिनचर्या से ज्ञात की जा सकने वाली बातों पर आधारित हैं। तथ्य यह है कि स्टार जहाजों, अंतरिक्ष स्टेशनों और क्षुद्रग्रहों के बारे में हम जो जानते हैं या कल्पना करते हैं, उसके आधार पर 'प्रिंट' का आउटपुट हमारे लिए मनुष्य के रूप में समझ में आता है, यह केवल तार्किक योजना या संयोग है। SPACE_OBJECT को उसके डिसेंडेन्ट्स के किसी विशिष्ट ज्ञान के साथ प्रोग्राम नहीं किया गया है।

deferred class
SPACE_OBJECT
feature {NONE} -- Initialization
make_with_name (a_name: like name; a_position: like position)
    -- Initialize Current with `a_name' and `a_position'.
  do
    name := a_name
    position := a_position
    sensor_data_agent := agent sensor_data
    encounter_agent := agent encounter
  ensure
    name_set: name.same_string (a_name)
    position_set: position.same_string (a_position)
  end
feature -- Access
encounter_agent: PROCEDURE [ANY, TUPLE]
    -- Agent for managing encounters with Current.
sensor_data_agent: FUNCTION [ANY, TUPLE, attached like sensor_data_anchor]
    -- Agent for returning sensor data of Current.
feature -- Settings
set_position (a_position: like position)
    -- Set `position' with `a_position'.
  do
    print (type + " " + name + " changes position from " + position + " to " + a_position + ".%N")
    position := a_position
  ensure
    position_set: position.same_string (a_position)
  end
feature {NONE} -- Implementation
encounter (a_sensor_agent: FUNCTION [ANY, TUPLE, attached like sensor_data_anchor])
    -- Detect and report on collision status of Current with `a_radar_agent'.
  do
    a_sensor_agent.call ([Void])
    check attached {like sensor_data_anchor} a_sensor_agent.last_result as al_sensor_data then
      if not name.same_string (al_sensor_data.name) then
        if (position.same_string (al_sensor_data.position)) then
          if ((al_sensor_data.is_dockable and is_dockable) and
              (is_manned and al_sensor_data.is_manned) and
              (is_manueverable and al_sensor_data.is_not_manueverable)) then
            print (type + " " + name + " is near " + al_sensor_data.type + " " +
                al_sensor_data.name + " and is dockable.%N")
          elseif ((is_dockable and al_sensor_data.is_dockable) and
                (is_manned and al_sensor_data.is_manned) and
                (is_manueverable and al_sensor_data.is_manueverable)) then
            print (type + " " + name + " beams a science team to " + al_sensor_data.type + " " +
                al_sensor_data.name + " as they pass!%N")
          elseif (is_manned and al_sensor_data.is_not_manned) then
            print (type + " " + name + " takes evasive action, avoiding " +
                al_sensor_data.type + " `" + al_sensor_data.name + "'!%N")
          end
        end
      end
    end
  end
name: STRING
    -- Name of Current.
type: STRING
    -- Type of Current.
  deferred
  end
position: STRING
    -- Position of Current.
is_dockable: BOOLEAN
    -- Is Current dockable with another manned object?
  deferred
  end
is_manned: BOOLEAN
    -- Is Current a manned object?
  deferred
  end
is_manueverable: BOOLEAN
    -- Is Current capable of being moved?
  deferred
  end
sensor_data: attached like sensor_data_anchor
    -- Sensor data of Current.
  do
      Result := [name, type, position, is_dockable, not is_dockable, is_manned, not is_manned, is_manueverable, not is_manueverable]
    end

  sensor_data_anchor: detachable TUPLE [name, type, position: STRING; is_dockable, is_not_dockable, is_manned, is_not_manned, is_manueverable, is_not_manueverable: BOOLEAN]
      -- Sensor data type anchor of Current.

end

SPACE_OBJECT के तीन वंशज वर्ग हैं:

SPACE_OBJECT
ASTEROID
SPACESHIP
SPACESTATION

हमारे उदाहरण में, क्षुद्रग्रह वर्ग का उपयोग 'रोग्यु' वस्तुओं के लिए किया जाता है, दो सितारा जहाजों के लिए स्पेसशिप और डीप स्पेस नाइन के लिए स्पेसस्टेशन का उपयोग किया जाता है। प्रत्येक वर्ग में, एकमात्र विशेषज्ञता 'टाइप' सुविधा और वस्तु के कुछ गुणों की सेटिंग है। रचना क्रम में 'नाम' के साथ-साथ 'पद' भी दिया जाता है।

उदाहरण के लिए: नीचे स्पेसशिप उदाहरण है।

class
SPACESHIP
inherit
SPACE_OBJECT
create
make_with_name
feature {NONE} -- Implementation
type: STRING = "Starship"
  -- <Precursor>
is_dockable: BOOLEAN = True
  -- <Precursor>
is_manned: BOOLEAN = True
  -- <Precursor>
is_manueverable: BOOLEAN = True
  -- <Precursor>
end

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

ध्यान दें कि समान टाइप और नाम वाली वस्तुओं को एक ही वस्तु माना जाता है, इसलिए तार्किक रूप से वार्तालाप की अनुमति नहीं है।

एफिल उदाहरण निष्कर्ष

डबल-डिस्पैच के संबंध में, एफिल डिजाइनर और प्रोग्रामर को क्लास रूटीन को एजेंट बनाकर और फिर डायरेक्ट ऑब्जेक्ट फीचर कॉल करने के अतिरिक्त उन एजेंटों को पास करके उनकी कक्षाओं से क्लास रूटीन को अलग करके प्रत्यक्ष ऑब्जेक्ट-टू-ऑब्जेक्ट ज्ञान के स्तर को हटाने की अनुमति देता है। एजेंटों के पास विशिष्ट हस्ताक्षर और संभावित परिणाम (प्रश्नों के स्थितियों में) भी होते हैं, जिससे वे विशिष्ट वस्तु विवरण छोड़े बिना आदर्श स्थैतिक टाइप की जांच करने वाले वाहन बन जाते हैं। एजेंट पूरी तरह से बहुरूपी होते हैं, इसलिए परिणामी कोड में केवल अपना स्थानीय कार्य पूरा करने के लिए आवश्यक विशिष्ट ज्ञान होता है। अन्यथा, कई सह-संस्करण वस्तुओं के आसपास विशिष्ट आंतरिक वर्ग सुविधा ज्ञान फैलने से कोई देखभाल का बोझ नहीं बढ़ता है। एजेंटों का उपयोग और यांत्रिकी यह सुनिश्चित करती है।

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

यह भी देखें

  • विज़िटर पैटर्न
  • मल्टीप्ल डिस्पैच
  • ट्रिविअल हैश फंक्शन
  • आभासी तालिका

संदर्भ

  1. A Simple Technique for Handling Multiple Polymorphism. In Proceedings of OOPSLA '86, Object–Oriented Programming Systems, Languages and Applications, pages 347–349, November 1986. Printed as SIGPLAN Notices, 21(11). ISBN 0-89791-204-7
  2. More Effective C++ by Scott Meyers(Addison-Wesley, 1996)
  3. "टाइप डायनामिक का उपयोग करना (सी# प्रोग्रामिंग गाइड)". Microsoft Developer Network. Microsoft. 30 Sep 2009. Retrieved 25 May 2016. ... Overload resolution occurs at run time instead of at compile time if one or more of the arguments in a method call have the type dynamic ...