सिंग्लटन कब उपयुक्त है? [बन्द है]


65

कुछ ने माना कि सिंगलटन पैटर्न हमेशा एक विरोधी पैटर्न है। तुम क्या सोचते हो?


अभी के लिए, मैं सिंगलनेट के बारे में सभी चर्चाओं के लिए इस लिंक को पसंद करता हूं ।
क्रेगॉक्स

1
यह भी देखें stackoverflow.com/a/138012/246724
बजे

जवाबों:


32

सिंगलेट्स की दो मुख्य आलोचनाएं मेरे द्वारा देखे गए दो शिविरों में आती हैं:

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

इन दोनों के परिणामस्वरूप, एक सामान्य दृष्टिकोण इन वर्गों के एक एकल उदाहरण को धारण करने के लिए एक व्यापक कंटेनर ऑब्जेक्ट बनाने का उपयोग करना है और केवल कंटेनर ऑब्जेक्ट इस प्रकार की कक्षाओं को संशोधित करता है, जबकि कई अन्य वर्गों को उनसे उपयोग करने की अनुमति दी जा सकती है कंटेनर वस्तु।


6
मैं केवल यह कहना चाहूंगा कि आप जावा में JMockit ( code.google.com/p/jmockit ) के साथ स्थैतिक तरीकों का मजाक उड़ा सकते हैं । यह बहुत काम का उपकरण है।
माइकल के

3
कुछ विचार: कंटेनर एक सिंगलटन है, इसलिए आपने सिंग्लेटन्स से छुटकारा नहीं पाया है। इसके अलावा, यदि आप एक सार्वजनिक एपीआई के साथ एक पुस्तकालय लिख रहे हैं, तो आप अपने एपीआई के उपयोगकर्ता को अपने कंटेनर का उपयोग करने के लिए मजबूर नहीं कर सकते । यदि आपको अपने पुस्तकालय में वैश्विक संसाधन प्रबंधक की आवश्यकता है (उदाहरण के लिए एकल भौतिक संसाधन तक पहुंच की रक्षा करना), तो आपको एक सिंगलटन का उपयोग करने की आवश्यकता है।
स्कॉट व्हिटलॉक

2
@Scott Whitlock को एक सिंगलटन होने की आवश्यकता क्यों है? सिर्फ इसलिए कि केवल एक ही उदाहरण ऐसा नहीं है। कोई भी IoC पुस्तकालय इस तरह की निर्भरता का प्रबंधन करेगा ...
MattDavey

इस समाधान ने प्रस्तावित किया कि इसे टूलबॉक्स के
क्रैगॉक्स

41

मैं मानता हूं कि यह एक विरोधी पैटर्न है। क्यों? क्योंकि यह आपके कोड को उसकी निर्भरता के बारे में झूठ बोलने की अनुमति देता है, और आप अन्य प्रोग्रामर पर भरोसा नहीं कर सकते हैं ताकि आपके पहले अपरिवर्तनीय एकल में पारस्परिक स्थिति का परिचय न हो सके।

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


काश मैं एक से अधिक बार उत्थान कर पाता!
मैटवेवी

34

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

इसी तरह, सिंग्लेटों के बारे में मेरी राय यह है कि यदि वे किसी कार्यक्रम के प्रतीत नहीं होने वाले हिस्सों के बीच परस्पर स्थिति को पार करने के लिए उपयोग किए जाते हैं तो ही वे खराब हैं। यदि उनके पास उत्परिवर्तनीय स्थिति नहीं है, या यदि उनके द्वारा किए जाने वाले उत्परिवर्तित राज्य को पूरी तरह से समझाया गया है, ताकि ऑब्जेक्ट के उपयोगकर्ताओं को इसके बारे में एक बहुस्तरीय वातावरण में भी पता न चले, तो उनके साथ कुछ भी गलत नहीं है।


3
तो दूसरे शब्दों में आप एक प्रोग्राम में डेटाबेस के किसी भी उपयोग के खिलाफ हैं।
केंडल हेल्मसटेटर गेलनर

एक प्रसिद्ध गूगल टेक टॉक वीडियो है, जो आपकी राय echos youtube.com/watch?v=-FRm3VPhseI
मार्टिन यॉर्क

2
@KendallHelmstetterGelner: राज्य और द्वितीयक भंडारण के बीच अंतर है। यह संभव नहीं है कि आप मेमोरी में एक संपूर्ण DB रख सकें।
मार्टिन यॉर्क

7

लोग इसका उपयोग क्यों करते हैं?

मैंने पीएचपी दुनिया में काफी संख्या में सिंगलटन देखे हैं। मुझे ऐसा कोई उपयोग मामला याद नहीं है, जहाँ मुझे पैटर्न का औचित्य मिला हो। लेकिन मुझे लगता है कि मुझे प्रेरणा के बारे में एक विचार मिला कि लोगों ने इसका उपयोग क्यों किया।

  1. एकल उदाहरण

    "पूरे आवेदन में कक्षा सी के एकल उदाहरण का उपयोग करें।"

    यह "डिफ़ॉल्ट डेटाबेस कनेक्शन" के लिए एक उचित आवश्यकता है। इसका मतलब यह नहीं है कि आप कभी भी दूसरा db कनेक्शन नहीं बनाएंगे, इसका मतलब यह है कि आप आमतौर पर डिफ़ॉल्ट के साथ काम करते हैं।

  2. एकल तात्कालिकता

    "कक्षा सी को एक से अधिक बार (प्रक्रिया के अनुसार, अनुरोध, आदि) की अनुमति न दें।"

    यह केवल तभी प्रासंगिक है जब कक्षा को तत्काल करने से साइड इफेक्ट होंगे जो अन्य उदाहरणों के साथ संघर्ष करते हैं।

    अक्सर इन संघर्षों को घटक को फिर से डिज़ाइन करने से बचा जा सकता है - जैसे कि क्लास कंस्ट्रक्टर से साइड इफेक्ट्स को समाप्त करके। या उन्हें अन्य तरीकों से हल किया जा सकता है। लेकिन अभी भी कुछ कानूनी उपयोग के मामले हो सकते हैं।

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

    अन्यथा, इस धारणा को लागू करने की कोई आवश्यकता नहीं है। इसे लागू करने का अर्थ यह भी है कि आप इकाई परीक्षणों के लिए एक अलग उदाहरण नहीं बना सकते हैं।

  3. वैश्विक पहुंच।

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

    कीमत तंग युग्मन, छिपी निर्भरता और वैश्विक राज्य के बारे में सब कुछ खराब है। लेकिन आप शायद ये पहले से ही भुगत रहे हैं।

  4. आलसी तात्कालिकता।

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

विशिष्ट कार्यान्वयन

विशिष्ट कार्यान्वयन एक निजी कंस्ट्रक्टर के साथ एक वर्ग है, और एक स्थैतिक उदाहरण चर, और एक स्थिर getInstance () आलसी मध्यस्थता के साथ विधि है।

ऊपर वर्णित समस्याओं के अलावा, यह एकल जिम्मेदारी सिद्धांत के साथ काटता है , क्योंकि वर्ग अपने स्वयं के तात्कालिकता और जीवन चक्र को नियंत्रित करता है , अन्य जिम्मेदारियों के अलावा जो कक्षा पहले से ही है।

निष्कर्ष

कई मामलों में, आप एक सिंगलटन के बिना और वैश्विक राज्य के बिना एक ही परिणाम प्राप्त कर सकते हैं। इसके बजाय, आपको निर्भरता इंजेक्शन का उपयोग करना चाहिए, और आप एक निर्भरता इंजेक्शन कंटेनर पर विचार करना चाह सकते हैं ।

हालाँकि, ऐसे उपयोग के मामले हैं जहां आपके पास निम्नलिखित वैध आवश्यकताएं शेष हैं:

  • एकल उदाहरण (लेकिन एक पल का नहीं)
  • वैश्विक पहुंच (क्योंकि आप कांस्य युग के ढांचे के साथ काम कर रहे हैं)
  • आलसी तात्कालिकता (क्योंकि यह सिर्फ अच्छा है)

तो, इस मामले में आप क्या कर सकते हैं:

  • एक सार्वजनिक निर्माण के साथ एक वर्ग सी बनाएं, जिसे आप त्वरित करना चाहते हैं।

  • एक स्थिर उदाहरण चर और एक स्थिर S :: getInstance () विधि के साथ एक अलग वर्ग एस बनाएं, जो आलसी इंस्टेंटेशन के साथ हो, जो उदाहरण के लिए वर्ग C का उपयोग करेगा।

  • C. के निर्माण से सभी दुष्प्रभावों को हटा दें। इसके बजाय, इन साइड इफेक्ट्स को S :: getInstance () विधि में डालें।

  • यदि आपके पास उपरोक्त आवश्यकताओं के साथ एक से अधिक वर्ग हैं, तो आप छोटे स्थानीय सेवा कंटेनर के साथ वर्ग उदाहरणों का प्रबंधन करने के लिए विचार कर सकते हैं , और केवल कंटेनर के लिए स्थिर उदाहरण का उपयोग कर सकते हैं। तो, एस :: getContainer () आपको एक आलसी-त्वरित सेवा कंटेनर देगा, और आपको कंटेनर से अन्य ऑब्जेक्ट मिलते हैं।

  • जहाँ आप कर सकते हैं स्थिर getInstance () को कॉल करने से बचें। जब भी संभव हो, इसके बजाय निर्भरता इंजेक्शन का उपयोग करें। विशेष रूप से, यदि आप कई वस्तुओं के साथ कंटेनर दृष्टिकोण का उपयोग करते हैं जो एक दूसरे पर निर्भर करते हैं, तो इनमें से किसी को भी S :: getContainer () को कॉल नहीं करना चाहिए।

  • वैकल्पिक रूप से एक इंटरफ़ेस बनाएं जो वर्ग C को लागू करता है, और इसका उपयोग S :: getInstance () के रिटर्न मान को दस्तावेज़ित करने के लिए करता है।

(क्या हम अभी भी इसे सिंगलटन कहते हैं? मैं इसे टिप्पणी अनुभाग पर छोड़ता हूं ..)

लाभ:

  • आप किसी भी वैश्विक स्थिति को छूने के बिना, यूनिट परीक्षण के लिए सी का एक अलग उदाहरण बना सकते हैं।

  • उदाहरण प्रबंधन को वर्ग से ही अलग किया जाता है -> चिंताओं का पृथक्करण, एकल जिम्मेदारी सिद्धांत।

  • S :: getInstance () उदाहरण के लिए किसी भिन्न वर्ग का उपयोग करना, या गतिशील रूप से यह निर्धारित करना आसान है कि किस वर्ग का उपयोग करना है।


1

व्यक्तिगत रूप से मैं एकल का उपयोग करूँगा जब मुझे 1, 2, या 3 की आवश्यकता होगी, या विशेष रूप से वर्ग के लिए कुछ सीमित मात्रा में प्रश्न होंगे। या मैं अपनी कक्षा के उपयोगकर्ता को यह बताना चाहता हूं कि मैं नहीं चाहता कि मेरी कक्षा के कई उदाहरण इसके लिए ठीक से काम करें।

इसके अलावा मैं इसका उपयोग केवल तब करूंगा जब मुझे अपने कोड में लगभग हर जगह इसका उपयोग करने की आवश्यकता हो और मैं किसी ऑब्जेक्ट को प्रत्येक वर्ग या फ़ंक्शन के पैरामीटर के रूप में पारित नहीं करना चाहता।

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

जब तक इसका उपयोग न करने के लिए, उपरोक्त 3 देखें और उन्हें विपरीत में बदल दें।


3
-0 लेकिन मैं लगभग -1। अगर मैं वास्तव में आलसी हूं तो मैं ऐसा करने के बजाय एक सिंगलटन ब्यूट का उपयोग करने के बजाय इसे अपने कोड में हर जगह पास करूंगा। यदि मैं या स्थिर सदस्यों के लिए सक्षम हूं, तो मैं इसके बजाय वैश्विक संस्करण का उपयोग करूंगा। वैश्विक संस्करण वास्तव में बहुत बेहतर हैं (मेरे लिए) फिर एकल।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.