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

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

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

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

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

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

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

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

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

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

परिभाषा
डिज़ाइन पैटर्न विज़िटर को इस प्रकार परिभाषित करता है: "Represent[ing] an operation to be performed on elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates."

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

आउटपुट
 सामने बाएँ पहिये का दौरा सामने दाहिना पहिया घूम रहा है बाएँ पहिये का पिछला भाग देखना दाहिने पहिये का पिछला भाग देखना शरीर का दौरा विज़िटिंग इंजन विजिटिंग कार मेरे अगले बाएँ पहिये को लात मार रहा हूँ मेरे अगले दाहिने पहिये को लात मार रहा हूँ मेरे पिछले बाएँ पहिये को लात मार रहा हूँ मेरे पिछले दाहिने पहिये को लात मार रहा हूँ मेरे शरीर को हिलाना मेरा इंजन शुरू हो रहा है मेरी कार स्टार्ट हो रही है 

आउटपुट
 सामने-बाएँ-पहिया सामने-दायाँ-पहिया पिछला-बायाँ-पहिया पिछला-दायाँ-पहिया शरीर इंजन पहिए को आगे-बाएँ-पहिए पर 42 बार किक करना पहिए को आगे-दाएँ-पहिए पर 42 बार किक करना पहिए को पीछे-बाएँ-पहिए पर 42 बार किक करना पहिए को पीछे-दाएँ-पहिए पर 42 बार किक करना मुझे नहीं पता कि शरीर और 42 को कैसे बातचीत करनी चाहिए इंजन का इंजन 42 बार शुरू किया गया प्रतीक एबीसी का उपयोग करके प्रतीकात्मक रूप से सामने-बाएँ-पहिया को लात मारना प्रतीकात्मक रूप से प्रतीक एबीसी का उपयोग करते हुए सामने-दाएँ-पहिया को लात मारना प्रतीक एबीसी का प्रयोग करते हुए प्रतीकात्मक रूप से पीछे के बाएं पहिये को लात मारना प्रतीक एबीसी का प्रयोग करते हुए प्रतीकात्मक रूप से पीछे-दाएँ-पहिया को लात मारना मुझे नहीं पता कि शरीर और एबीसी को कैसे परस्पर क्रिया करनी चाहिए

प्रतीक एबीसीका उपयोग करके प्रतीकात्मक रूप से इंजन इंजन शुरू करना

टिप्पणियाँ
The  parameter is superfluous in. The reason is that it is possible to use an anonymous function that calls the desired target method with a lexically captured object:

Now, the multiple dispatch occurs in the call issued from the body of the anonymous function, and so  is just a mapping function that distributes a function application over the elements of an object. Thus all traces of the Visitor Pattern disappear, except for the mapping function, in which there is no evidence of two objects being involved. All knowledge of there being two objects and a dispatch on their types is in the lambda function.

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

अमूर्तन
पायथन 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