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

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

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

टैग किया गया संघ और पैटर्न मिलान वाली प्रोग्रामिंग भाषाएं विज़िटर पैटर्न के कई लाभों को समाप्त कर देती हैं, क्योंकि विज़िटर वर्ग ऑब्जेक्ट के प्रकार पर आसानी से शाखा लगाने में सक्षम होता है और यदि कोई नया ऑब्जेक्ट प्रकार परिभाषित किया जाता है, जिसे विज़िटर अभी तक संभाल नहीं पाता है, तब कंपाइलर त्रुटि उत्पन्न करता है।

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

विज़िटर डिज़ाइन पैटर्न किन समस्याओं का समाधान कर सकता है?

 * क्लासेस को बदले बिना किसी वस्तु संरचना के (कुछ) वर्गों के लिए नए ऑपरेशन को परिभाषित करना संभव होना चाहिए।

जब नए संचालन की बार-बार आवश्यकता होती है और वस्तु संरचना में कई असंबंधित वर्ग होते हैं, हर बार नए ऑपरेशन की आवश्यकता होने पर नए उपवर्ग जोड़ना अनम्य है क्योंकि [..] इन सभी परिचालनों को विभिन्न नोड वर्गों में वितरित करने से ऐसी प्रणाली बनती है जिसे समझना, बनाए रखना और बदलना कठिन है।

विज़िटर डिज़ाइन पैटर्न किस समाधान का वर्णन करता है?
इससे ऑब्जेक्ट संरचना के वर्गों से स्वतंत्र रूप से नए ऑपरेशन बनाना संभव हो जाता है नए विज़िटर ऑब्जेक्ट जोड़कर।
 * एक भिन्न (विज़िटर) ऑब्जेक्ट को परिभाषित करें जो ऑब्जेक्ट संरचना के अवयवों पर किए जाने वाले ऑपरेशन को कार्यान्वित करता है।
 * ग्राहक ऑब्जेक्ट संरचना को पार करते हैं और तत्व पर डिस्पैचिंग ऑपरेशन एक्सेप्ट (विज़िटर) को कॉल करते हैं - जो स्वीकृत विज़िटर ऑब्जेक्ट के लिए अनुरोध भेजता है (प्रतिनिधियों को)। विज़िटर ऑब्जेक्ट तब तत्व पर ऑपरेशन करता है (तत्व का दौरा करता है)।

नीचे यूएमएल वर्ग और अनुक्रम आरेख भी देखें।

परिभाषा
डिज़ाइन पैटर्न विज़िटर को इस प्रकार परिभाषित करता है: "किसी वस्तु संरचना के अवयवों पर किए जाने वाले ऑपरेशन का प्रतिनिधित्व करना हैं। विज़िटर आपको उन अवयवों की कक्षाओं को परिवर्तित किये बिना नया ऑपरेशन परिभाषित करने देता है जिन पर यह संचालित होता है।"

विज़िटर की प्रकृति इसे सार्वजनिक एपीआई में प्लग करने के लिए आदर्श पैटर्न बनाती है, इस प्रकार इसके ग्राहकों को सोर्स को संशोधित किए बिना विज़िटिंग क्लास का उपयोग करके क्लास पर संचालन करने की अनुमति मिलती है।

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

हालाँकि, इस पैटर्न का दोष यह है कि यह वर्ग पदानुक्रम में विस्तार को और अधिक कठिन बना देता है, क्योंकि नई क्लासेस को आम तौर पर नए की आवश्यकता होती है  प्रत्येक आगंतुक के लिए जोड़ी जाने वाली विधि।

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

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

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

इसके बजाय, विज़िटर पैटर्न प्रयुक्त किया जा सकता है. यह पूरे पदानुक्रम पर तार्किक ऑपरेशन (यानी सेव (इमेज_ट्री)) को वर्ग (यानी सेवर) में एनकोड करता है जो पेड़ को पार करने के लिए सामान्य तरीकों को प्रयुक्त करता है और प्रारूप विशिष्ट व्यवहारों के लिए प्रयुक्त किए जाने वाले वर्चुअल हेल्पर तरीकों (यानी सेव_सर्कल, सेव_स्क्वायर, आदि) का वर्णन करता है। सीएडी उदाहरण के मामले में, ऐसे प्रारूप विशिष्ट व्यवहार विज़िटर के उपवर्ग (यानी सेवरपीएनजी) द्वारा कार्यान्वित किए जाएंगे। इस प्रकार, प्रकार की जांच और ट्रैवर्सल चरणों के सभी दोहराव को हटा दिया जाता है। इसके अतिरिक्त, कंपाइलर अब शिकायत करता है कि क्या कोई आकृति छोड़ी गई है क्योंकि यह अब सामान्य बेस ट्रैवर्सल/सेव फ़ंक्शन द्वारा अपेक्षित है।

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

यूएमएल वर्ग और अनुक्रम आरेख
उपरोक्त एकीकृत मॉडलिंग भाषा वर्ग आरेख में,  क्लास सीधे कोई नया ऑपरेशन प्रयुक्त नहीं करता है। बजाय,  डिस्पैच ऑपरेशन कार्यान्वित करता है   जो स्वीकृत विज़िटर ऑब्जेक्ट के लिए अनुरोध भेजता है (प्रतिनिधियों को) ).   ई> क्लास ऑपरेशन प्रयुक्त करता है .  फिर प्रयुक्त करता है   को भेजकर  .   ई> क्लास ऑपरेशन प्रयुक्त करता है.

एकीकृत मॉडलिंग भाषा अनुक्रम आरेख रन-टाइम इंटरैक्शन दिखाता है:  ई>ऑब्जेक्ट किसी ऑब्जेक्ट संरचना के अवयवों का पता लगाता है  और कॉल करता है   प्रत्येक तत्व पर. पूर्व  कॉल   पर , जो कॉल करता है  स्वीकृत पर   वस्तु। तत्व स्वयं को पारित कर दिया गया है   ताकि यह दौरा कर सकता है  (पुकारना  ). इसके पश्चात्  कॉल   पर , जो कॉल करता है  पर   वह दौरा करता है   (कॉल करता है  ).

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

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

तत्व घोषित करता है  किसी आगंतुक को तर्क के रूप में लेते हुए उसे स्वीकार करने की विधि। तत्व वर्ग से प्राप्त ठोस तत्व, कार्यान्वयन करते हैं   तरीका। अपने सरलतम रूप में, यह आगंतुकों के लिए कॉल से अधिक कुछ नहीं है   तरीका। समग्र पैटर्न तत्व, जो बाल वस्तुओं की सूची बनाए रखते हैं, आम तौर पर प्रत्येक बच्चे को कॉल करते हुए, इन पर पुनरावृत्ति करते हैं   तरीका।

क्लाइंट प्रत्यक्ष या अप्रत्यक्ष रूप से ऑब्जेक्ट संरचना बनाता है, और ठोस विज़िटरों को तुरंत बुलाता है। जब कोई ऑपरेशन निष्पादित करना होता है जिसे विज़िटर पैटर्न का उपयोग करके कार्यान्वित किया जाता है, तब यह कॉल करता है  शीर्ष-स्तरीय तत्व की विधि।

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

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

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

सी# उदाहरण
यह उदाहरण भिन्न घोषणा करता है  वह वर्ग जो मुद्रण का ध्यान रखता है।

स्मॉलटॉक उदाहरण
इस मामले में, यह जानना ऑब्जेक्ट की ज़िम्मेदारी है कि स्ट्रीम पर खुद को कैसे प्रिंट किया जाए। यहाँ आगंतुक वस्तु है, धारा नहीं।

जाओ
गो ओवरलोडिंग का समर्थन नहीं करता है, इसलिए विज़िट विधियों को भिन्न-भिन्न नामों की आवश्यकता है। विशिष्ट विज़िटर इंटरफ़ेस हो सकता है

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

आउटपुट
"front-left-wheel" "front-right-wheel" "rear-left-wheel" "rear-right-wheel" "body" "engine" kicking wheel "front-left-wheel" 42 times kicking wheel "front-right-wheel" 42 times kicking wheel "rear-left-wheel" 42 times kicking wheel "rear-right-wheel" 42 times don't know how "body" and 42 should interact starting engine "engine" 42 times kicking wheel "front-left-wheel" symbolically using symbol ABC kicking wheel "front-right-wheel" symbolically using symbol ABC kicking wheel "rear-left-wheel" symbolically using symbol ABC kicking wheel "rear-right-wheel" symbolically using symbol ABC don't know how "body" and ABC should interact starting engine "engine" symbolically using symbol ABC

टिप्पणियाँ
में  पैरामीटर अतिश्योक्तिपूर्ण होते है। इसका कारण यह है कि अज्ञात फ़ंक्शन का उपयोग करना संभव है जो वांछित लक्ष्य विधि को शाब्दिक रूप से कैप्चर की गई वस्तु के साथ कॉल करता है |

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

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

एब्सट्रेक्शन
पायथन 3 या इसके पश्चात् के संस्करण का उपयोग करने से स्वीकृति विधि का सामान्य कार्यान्वयन करने की अनुमति मिलती है |

यदि कोई पूर्व से कार्यान्वित क्लासेस पर वापस आना चाहता है तब कोई इसे क्लास के विधि समाधान क्रम पर पुनरावृत्त करने के लिए बढ़ा सकता है। वह लुकअप को पूर्व से परिभाषित करने के लिए उपवर्ग हुक सुविधा का भी उपयोग कर सकते हैं।

रिलेटेड डिज़ाइन पैटर्न

 * इटरेटर पैटर्न - विज़िटर पैटर्न की तरह यह ट्रैवर्सल सिद्धांत को परिभाषित करता है,और यह ट्रैवर्स किए गए ऑब्जेक्ट के अंदर किसी भी प्रकार का भेदभाव किए बिना होता हैं
 * चर्च एन्कोडिंग -कार्यात्मक प्रोग्रामिंग से एक संबंधित अवधारणा, जिसमें टैग किए गए यूनियन/सम प्रकारों को ऐसे प्रकारों पर "विज़िटर" के व्यवहार का उपयोग करके मॉडल तैयार किया जा सकता है, और जो विज़िटर पैटर्न को वेरिएंट और पैटर्न का अनुकरण करने में सक्षम बनाता है।

यह भी देखें

 * बीजगणितीय डेटा प्रकार
 * डबल डिस्पैच
 * मल्टीपल डिस्पैच
 * फ़ंक्शन ऑब्जेक्ट

बाहरी संबंध

 * A rough chapter from The Principles, Patterns, and Practices of Agile Software Development, Robert C. Martin, Prentice Hall
 * Visitor pattern in UML and in LePUS3 (a Design Description Language)
 * Article "Componentization: the Visitor Example by Bertrand Meyer and Karine Arnout, Computer (IEEE), vol. 39, no. 7, July 2006, pages 23-30.
 * Article A Type-theoretic Reconstruction of the Visitor Pattern
 * Article "The Essence of the Visitor Pattern" by Jens Palsberg and C. Barry Jay. 1997 IEEE-CS COMPSAC paper showing that accept methods are unnecessary when reflection is available; introduces term 'Walkabout' for the technique.
 * Article "A Time for Reflection" by Bruce Wallace – subtitled "Java 1.2's reflection capabilities eliminate burdensome accept methods from your Visitor pattern"
 * Visitor Pattern using reflection(java).
 * PerfectJPattern Open Source Project, Provides a context-free and type-safe implementation of the Visitor Pattern in Java based on Delegates.
 * Visitor Design Pattern