कुछ ने माना कि सिंगलटन पैटर्न हमेशा एक विरोधी पैटर्न है। तुम क्या सोचते हो?
कुछ ने माना कि सिंगलटन पैटर्न हमेशा एक विरोधी पैटर्न है। तुम क्या सोचते हो?
जवाबों:
सिंगलेट्स की दो मुख्य आलोचनाएं मेरे द्वारा देखे गए दो शिविरों में आती हैं:
इन दोनों के परिणामस्वरूप, एक सामान्य दृष्टिकोण इन वर्गों के एक एकल उदाहरण को धारण करने के लिए एक व्यापक कंटेनर ऑब्जेक्ट बनाने का उपयोग करना है और केवल कंटेनर ऑब्जेक्ट इस प्रकार की कक्षाओं को संशोधित करता है, जबकि कई अन्य वर्गों को उनसे उपयोग करने की अनुमति दी जा सकती है कंटेनर वस्तु।
मैं मानता हूं कि यह एक विरोधी पैटर्न है। क्यों? क्योंकि यह आपके कोड को उसकी निर्भरता के बारे में झूठ बोलने की अनुमति देता है, और आप अन्य प्रोग्रामर पर भरोसा नहीं कर सकते हैं ताकि आपके पहले अपरिवर्तनीय एकल में पारस्परिक स्थिति का परिचय न हो सके।
एक वर्ग में एक कंस्ट्रक्टर हो सकता है जो केवल एक स्ट्रिंग लेता है, इसलिए आपको लगता है कि यह अलगाव में त्वरित है और इसके दुष्प्रभाव नहीं हैं। हालाँकि, चुपचाप, यह किसी प्रकार की सार्वजनिक, ग्लोबली रूप से उपलब्ध सिंगलटन ऑब्जेक्ट के साथ संचार कर रहा है, ताकि जब भी आप क्लास को इंस्टेंट करें, तो इसमें अलग-अलग डेटा शामिल हों। यह न केवल आपके एपीआई के उपयोगकर्ताओं के लिए, बल्कि कोड की परीक्षा के लिए भी एक बड़ी समस्या है। कोड को ठीक से यूनिट-टेस्ट करने के लिए, आपको लगातार परीक्षण के परिणाम प्राप्त करने के लिए सिंगलटन में वैश्विक स्थिति का सूक्ष्म प्रबंधन करना होगा।
सिंगलटन पैटर्न मूल रूप से केवल एक आलसी प्रारंभिक वैश्विक चर है। वैश्विक चर आमतौर पर और सही रूप से बुराई माने जाते हैं क्योंकि वे किसी प्रोग्राम के प्रतीत नहीं होने वाले हिस्सों के बीच की दूरी पर डरावना कार्रवाई की अनुमति देते हैं। हालांकि, आईएमएचओ वैश्विक चर के साथ कुछ भी गलत नहीं है जो एक कार्यक्रम से शुरू होने वाली दिनचर्या (उदाहरण के लिए, एक कॉन्फिग फ़ाइल या कमांड लाइन तर्कों को पढ़कर) और उसके बाद स्थिरांक के रूप में माना जाता है। वैश्विक चर का ऐसा उपयोग केवल पत्र में अलग है, भावना में नहीं, संकलन समय पर नामांकित निरंतर होने से।
इसी तरह, सिंग्लेटों के बारे में मेरी राय यह है कि यदि वे किसी कार्यक्रम के प्रतीत नहीं होने वाले हिस्सों के बीच परस्पर स्थिति को पार करने के लिए उपयोग किए जाते हैं तो ही वे खराब हैं। यदि उनके पास उत्परिवर्तनीय स्थिति नहीं है, या यदि उनके द्वारा किए जाने वाले उत्परिवर्तित राज्य को पूरी तरह से समझाया गया है, ताकि ऑब्जेक्ट के उपयोगकर्ताओं को इसके बारे में एक बहुस्तरीय वातावरण में भी पता न चले, तो उनके साथ कुछ भी गलत नहीं है।
मैंने पीएचपी दुनिया में काफी संख्या में सिंगलटन देखे हैं। मुझे ऐसा कोई उपयोग मामला याद नहीं है, जहाँ मुझे पैटर्न का औचित्य मिला हो। लेकिन मुझे लगता है कि मुझे प्रेरणा के बारे में एक विचार मिला कि लोगों ने इसका उपयोग क्यों किया।
एकल उदाहरण ।
"पूरे आवेदन में कक्षा सी के एकल उदाहरण का उपयोग करें।"
यह "डिफ़ॉल्ट डेटाबेस कनेक्शन" के लिए एक उचित आवश्यकता है। इसका मतलब यह नहीं है कि आप कभी भी दूसरा db कनेक्शन नहीं बनाएंगे, इसका मतलब यह है कि आप आमतौर पर डिफ़ॉल्ट के साथ काम करते हैं।
एकल तात्कालिकता ।
"कक्षा सी को एक से अधिक बार (प्रक्रिया के अनुसार, अनुरोध, आदि) की अनुमति न दें।"
यह केवल तभी प्रासंगिक है जब कक्षा को तत्काल करने से साइड इफेक्ट होंगे जो अन्य उदाहरणों के साथ संघर्ष करते हैं।
अक्सर इन संघर्षों को घटक को फिर से डिज़ाइन करने से बचा जा सकता है - जैसे कि क्लास कंस्ट्रक्टर से साइड इफेक्ट्स को समाप्त करके। या उन्हें अन्य तरीकों से हल किया जा सकता है। लेकिन अभी भी कुछ कानूनी उपयोग के मामले हो सकते हैं।
आपको इस बारे में भी सोचना चाहिए कि क्या "केवल एक" आवश्यकता का अर्थ "एक प्रति प्रक्रिया" है। उदाहरण के लिए, संसाधन की समयावधि के लिए, आवश्यकता "प्रति संपूर्ण प्रणाली, प्रक्रियाओं में एक" और "एक प्रति प्रक्रिया" नहीं है। और अन्य चीजों के लिए यह "अनुप्रयोग संदर्भ" के अनुसार है, और आप बस प्रति प्रक्रिया एक आवेदन संदर्भ होना चाहिए।
अन्यथा, इस धारणा को लागू करने की कोई आवश्यकता नहीं है। इसे लागू करने का अर्थ यह भी है कि आप इकाई परीक्षणों के लिए एक अलग उदाहरण नहीं बना सकते हैं।
वैश्विक पहुंच।
यह केवल तभी वैध है जब आपके पास उन ऑब्जेक्ट्स को पास करने के लिए कोई उचित बुनियादी ढांचा नहीं है, जहां उनका उपयोग किया जाता है। इसका मतलब यह हो सकता है कि आपका ढांचा या वातावरण बेकार है, लेकिन इसे ठीक करने के लिए आपकी शक्तियों के भीतर नहीं हो सकता है।
कीमत तंग युग्मन, छिपी निर्भरता और वैश्विक राज्य के बारे में सब कुछ खराब है। लेकिन आप शायद ये पहले से ही भुगत रहे हैं।
आलसी तात्कालिकता।
यह एक सिंगलटन का आवश्यक हिस्सा नहीं है, लेकिन यह उन्हें लागू करने का सबसे लोकप्रिय तरीका लगता है। लेकिन, जबकि आलसी तात्कालिकता के लिए एक अच्छी बात है, आपको इसे प्राप्त करने के लिए वास्तव में एक सिंगलटन की आवश्यकता नहीं है।
विशिष्ट कार्यान्वयन एक निजी कंस्ट्रक्टर के साथ एक वर्ग है, और एक स्थैतिक उदाहरण चर, और एक स्थिर getInstance () आलसी मध्यस्थता के साथ विधि है।
ऊपर वर्णित समस्याओं के अलावा, यह एकल जिम्मेदारी सिद्धांत के साथ काटता है , क्योंकि वर्ग अपने स्वयं के तात्कालिकता और जीवन चक्र को नियंत्रित करता है , अन्य जिम्मेदारियों के अलावा जो कक्षा पहले से ही है।
कई मामलों में, आप एक सिंगलटन के बिना और वैश्विक राज्य के बिना एक ही परिणाम प्राप्त कर सकते हैं। इसके बजाय, आपको निर्भरता इंजेक्शन का उपयोग करना चाहिए, और आप एक निर्भरता इंजेक्शन कंटेनर पर विचार करना चाह सकते हैं ।
हालाँकि, ऐसे उपयोग के मामले हैं जहां आपके पास निम्नलिखित वैध आवश्यकताएं शेष हैं:
तो, इस मामले में आप क्या कर सकते हैं:
एक सार्वजनिक निर्माण के साथ एक वर्ग सी बनाएं, जिसे आप त्वरित करना चाहते हैं।
एक स्थिर उदाहरण चर और एक स्थिर S :: getInstance () विधि के साथ एक अलग वर्ग एस बनाएं, जो आलसी इंस्टेंटेशन के साथ हो, जो उदाहरण के लिए वर्ग C का उपयोग करेगा।
C. के निर्माण से सभी दुष्प्रभावों को हटा दें। इसके बजाय, इन साइड इफेक्ट्स को S :: getInstance () विधि में डालें।
यदि आपके पास उपरोक्त आवश्यकताओं के साथ एक से अधिक वर्ग हैं, तो आप छोटे स्थानीय सेवा कंटेनर के साथ वर्ग उदाहरणों का प्रबंधन करने के लिए विचार कर सकते हैं , और केवल कंटेनर के लिए स्थिर उदाहरण का उपयोग कर सकते हैं। तो, एस :: getContainer () आपको एक आलसी-त्वरित सेवा कंटेनर देगा, और आपको कंटेनर से अन्य ऑब्जेक्ट मिलते हैं।
जहाँ आप कर सकते हैं स्थिर getInstance () को कॉल करने से बचें। जब भी संभव हो, इसके बजाय निर्भरता इंजेक्शन का उपयोग करें। विशेष रूप से, यदि आप कई वस्तुओं के साथ कंटेनर दृष्टिकोण का उपयोग करते हैं जो एक दूसरे पर निर्भर करते हैं, तो इनमें से किसी को भी S :: getContainer () को कॉल नहीं करना चाहिए।
वैकल्पिक रूप से एक इंटरफ़ेस बनाएं जो वर्ग C को लागू करता है, और इसका उपयोग S :: getInstance () के रिटर्न मान को दस्तावेज़ित करने के लिए करता है।
(क्या हम अभी भी इसे सिंगलटन कहते हैं? मैं इसे टिप्पणी अनुभाग पर छोड़ता हूं ..)
लाभ:
आप किसी भी वैश्विक स्थिति को छूने के बिना, यूनिट परीक्षण के लिए सी का एक अलग उदाहरण बना सकते हैं।
उदाहरण प्रबंधन को वर्ग से ही अलग किया जाता है -> चिंताओं का पृथक्करण, एकल जिम्मेदारी सिद्धांत।
S :: getInstance () उदाहरण के लिए किसी भिन्न वर्ग का उपयोग करना, या गतिशील रूप से यह निर्धारित करना आसान है कि किस वर्ग का उपयोग करना है।
व्यक्तिगत रूप से मैं एकल का उपयोग करूँगा जब मुझे 1, 2, या 3 की आवश्यकता होगी, या विशेष रूप से वर्ग के लिए कुछ सीमित मात्रा में प्रश्न होंगे। या मैं अपनी कक्षा के उपयोगकर्ता को यह बताना चाहता हूं कि मैं नहीं चाहता कि मेरी कक्षा के कई उदाहरण इसके लिए ठीक से काम करें।
इसके अलावा मैं इसका उपयोग केवल तब करूंगा जब मुझे अपने कोड में लगभग हर जगह इसका उपयोग करने की आवश्यकता हो और मैं किसी ऑब्जेक्ट को प्रत्येक वर्ग या फ़ंक्शन के पैरामीटर के रूप में पारित नहीं करना चाहता।
इसके अलावा मैं केवल एक सिंगलटन का उपयोग करूंगा यदि यह दूसरे फ़ंक्शन के संदर्भात्मक पारदर्शिता को नहीं तोड़ता है। कुछ इनपुट दिए जाने का मतलब यह हमेशा एक ही आउटपुट देगा। यानी मैं इसे वैश्विक स्थिति के लिए इस्तेमाल नहीं करता। जब तक कि संभवतः वैश्विक स्थिति एक बार आरंभिक नहीं हो जाती और कभी नहीं बदली जाती।
जब तक इसका उपयोग न करने के लिए, उपरोक्त 3 देखें और उन्हें विपरीत में बदल दें।