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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

यूएमएल वर्ग और अनुक्रम आरेख


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

फिर  को भेजकर   प्रयुक्त करता है। और   वर्ग ऑपरेशन  प्रयुक्त करता है।

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

इसके पश्चात्  कॉल   पर , जो कॉल करता है  पर   वह दौरा करता है   (कॉल करता है  ).

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

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

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

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

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

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

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

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

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

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

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

आउटपुट
"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