तो सिंगलेट्स खराब हैं, फिर क्या?


553

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

यहाँ एक प्रमुख हालिया परियोजना से मैं एक वास्तविक उदाहरण प्रस्तुत करता हूँ:

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

क्या कोई अन्य दृष्टिकोण है जो मूल रूप से इस तरह के वैश्विक डेटा प्रबंधक कैश ऑब्जेक्ट होने से उपयुक्त हो सकता है? इस ऑब्जेक्ट को आधिकारिक तौर पर "सिंगलटन" होना निश्चित रूप से नहीं है, लेकिन यह अवधारणा को एक होने का मतलब देता है। यहाँ एक अच्छा स्वच्छ विकल्प क्या है?


10
सिंग्लटन के उपयोग को हल करने में क्या समस्या है? विकल्प (जैसे स्थिर वर्ग) की तुलना में उस समस्या को हल करना बेहतर कैसे है?
आनन।

14
@ बंदूक: एक स्थिर वर्ग का उपयोग कैसे स्थिति को बेहतर बनाता है। अभी भी तंग युग्मन है?
मार्टिन यॉर्क

5
@ मॉर्टिन: मैं यह सुझाव नहीं दे रहा हूं कि यह "बेहतर" है। मैं सुझाव दे रहा हूं कि ज्यादातर मामलों में, एक सिंगलटन एक समस्या की तलाश में एक समाधान है।
आनन।

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

7
@ चेतावनी: यदि आप केवल सिंगलटन तक पहुंच को सिंक्रनाइज़ कर रहे हैं, तो आपकी संगति टूट गई है । सिंगलटन ऑब्जेक्ट को लाने के बाद आपके धागे को बाधित किया जा सकता है, एक और धागा आता है, और ब्लेम, रेस की स्थिति। एक स्थिर वर्ग के बजाय एक सिंगलटन का उपयोग करना, ज्यादातर मामलों में, बस चेतावनी के संकेत को दूर कर रहा है और सोच रहा है कि समस्या को हल करता है
आनन।

जवाबों:


809

एकल उदाहरणों और सिंगलटन डिज़ाइन पैटर्न के बीच अंतर करना महत्वपूर्ण है ।

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

सिंगलटन पैटर्न पैटर्न एक विशेष प्रकार का एकल उदाहरण है, विशेष रूप से एक:

  • एक वैश्विक, स्थिर उदाहरण क्षेत्र के माध्यम से सुलभ;
  • या तो प्रोग्राम इनिशियलाइज़ेशन पर या पहली पहुँच पर;
  • कोई भी सार्वजनिक निर्माणकर्ता (सीधे संपर्क नहीं कर सकता);
  • कभी भी स्पष्ट रूप से मुक्त नहीं किया गया (कार्यक्रम समाप्ति पर स्पष्ट रूप से मुक्त)।

यह इस विशिष्ट डिजाइन विकल्प के कारण है कि पैटर्न कई संभावित दीर्घकालिक समस्याओं का परिचय देता है:

  • सार या इंटरफ़ेस वर्गों का उपयोग करने में असमर्थता;
  • उपवर्ग में असमर्थता;
  • आवेदन भर में उच्च युग्मन (संशोधित करने के लिए मुश्किल);
  • परीक्षण करने में कठिनाई (यूनिट परीक्षणों में नकली / नकली नहीं हो सकती);
  • उत्परिवर्तनीय स्थिति (व्यापक लॉकिंग की आवश्यकता होती है) के मामले में समानांतर करना मुश्किल;
  • और इसी तरह।

इन लक्षणों में से कोई भी वास्तव में एकल उदाहरणों के लिए स्थानिक नहीं है, बस सिंगलटन पैटर्न है।

इसके बदले आप क्या कर सकते हैं? बस सिंगलटन पैटर्न का उपयोग न करें।

प्रश्न से उद्धरण:

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

इस अवधारणा का एक नाम है, जैसा कि आप संकेत की तरह लेकिन ध्वनि अनिश्चित के। इसे कैची कहा जाता है । यदि आप फैंसी प्राप्त करना चाहते हैं, तो आप इसे "ऑफ़लाइन कैश" या दूरस्थ डेटा की ऑफ़लाइन प्रतिलिपि कह सकते हैं।

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

पहली बात मैं कैश के विभिन्न कार्यात्मक क्षेत्रों को अलग-अलग इंटरफेस में अलग करता हूं । उदाहरण के लिए, मान लें कि आप Microsoft Access के आधार पर दुनिया का सबसे खराब YouTube क्लोन बना रहे हैं:

                          MSAccessCache
                                ▲
                                |
              + ----------------- + ----------------- +
              | | |
         IMediaCache IProfileCache IPageCache
              | | |
              | | |
          वीडियोपेज MyAccountPage MostPopularPage

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

इसे डिपेंडेंसी इंजेक्शन कहा जाता है ; आपको बसंत या किसी विशेष आईओसी कंटेनर का उपयोग करने की आवश्यकता नहीं है, जब तक कि आपका सामान्य वर्ग डिज़ाइन कॉल करने वाले की निर्भरता को स्वीकार नहीं करता है, बजाय इसके कि वे स्वयं या वैश्विक स्थिति का संदर्भ दें

आपको इंटरफ़ेस-आधारित डिज़ाइन का उपयोग क्यों करना चाहिए? तीन कारण:

  1. यह कोड को पढ़ना आसान बनाता है; आप स्पष्ट रूप से उन इंटरफेस से समझ सकते हैं जो निर्भर वर्गों पर निर्भर करते हैं।

  2. यदि और जब आपको पता चलता है कि Microsoft Access डेटा बैक-एंड के लिए सबसे अच्छा विकल्प नहीं था, तो आप इसे कुछ बेहतर तरीके से बदल सकते हैं - मान लें कि SQL सर्वर।

  3. यदि और जब आपको पता चलता है कि SQL सर्वर विशेष रूप से मीडिया के लिए सबसे अच्छा विकल्प नहीं है , तो आप सिस्टम के किसी अन्य भाग को प्रभावित किए बिना अपने कार्यान्वयन को तोड़ सकते हैं । यहीं से अमूर्तता की वास्तविक शक्ति सामने आती है।

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

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

                                                        + - IMediaRepository
                                                        |
                          कैश (सामान्य) --------------- + - IProfileRepository
                                ▲ |
                                | + - IPageRepository
              + ----------------- + ----------------- +
              | | |
         IMediaCache IProfileCache IPageCache
              | | |
              | | |
          वीडियोपेज MyAccountPage MostPopularPage

इसका लाभ यह है कि आपको कभी भी अपने Cacheउदाहरण को तोड़ने की ज़रूरत नहीं है यदि आप रिफ्लेक्टर का फैसला करते हैं; आप यह बदल सकते हैं कि कैसे मीडिया को इसे केवल एक वैकल्पिक कार्यान्वयन खिलाकर संग्रहीत किया जाता है IMediaRepository। यदि आप सोचते हैं कि यह एक साथ कैसे फिट बैठता है, तो आप देखेंगे कि यह अभी भी कभी-कभी केवल एक कैश का भौतिक उदाहरण बनाता है, इसलिए आपको कभी भी एक ही डेटा को दो बार लाने की आवश्यकता नहीं है।

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

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


131
पहली पोस्ट मैंने कभी पढ़ी है जो वास्तव में DI को वैश्विक राज्य के विकल्प के रूप में समझाती है। इस समय और प्रयास के लिए धन्यवाद। इस पोस्ट के परिणामस्वरूप हम सभी बेहतर हैं।
मृलेन

4
कैश एक सिंगलटन क्यों नहीं हो सकता? क्या यह एक सिंगलटन नहीं है यदि आप इसे पास करते हैं और निर्भरता इंजेक्शन का उपयोग करते हैं? सिंगलटन सिर्फ एक उदाहरण के लिए खुद को सीमित करने के बारे में है, न कि यह कि इसे सही तरीके से एक्सेस कैसे किया जाता है? : पर यह मेरा ले देखें assoc.tumblr.com/post/51302471844/the-misunderstood-singleton
एरिक Engheim

29
@AdamSmith: आप वास्तव में पढ़ी किसी भी इस जवाब की? आपके प्रश्न का उत्तर पहले दो पैराग्राफ में दिया गया है। सिंगलटन पैटर्न! == एकल उदाहरण।
Aaronaught

5
@ कवास और एडम स्मिथ - आपके लिंक को पढ़कर मुझे लगता है कि आपने वास्तव में इस उत्तर को नहीं पढ़ा है - सब कुछ पहले से ही है।
विल्बर्ट

19
@ कवास मुझे लगता है कि इस उत्तर का मांस एकल-उदाहरण और सिंगलटन के बीच का अंतर है। सिंगलटन खराब है, एकल-उदाहरण नहीं है। डिपेंडेंसी इंजेक्शन सिंगललेट्स का उपयोग किए बिना एकल उदाहरणों का उपयोग करने का एक अच्छा, सामान्य तरीका है।
विल्बर्ट

48

आपके द्वारा दिए गए मामले में, ऐसा लगता है कि एक सिंगलटन का उपयोग समस्या नहीं है, बल्कि एक समस्या का लक्षण है - एक बड़ी, वास्तुशिल्प समस्या।

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

मुद्दा यह है कि सिस्टम के कुछ हिस्सों के बीच निर्भरता सही ढंग से स्थापित नहीं है, और यह संभवतः प्रणालीगत है।

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

फिर, हम बड़े पैमाने पर वास्तुकला और डिजाइन के मुद्दों को देख रहे हैं।

इसके अलावा, यह समझना बहुत महत्वपूर्ण है कि किसी वस्तु का जीवनकाल पूरी तरह से तलाक हो सकता है कि वस्तु को उपयोग के लिए कैसे पाया जाता है।

एक कैश को जीवन भर एप्लिकेशन के लिए रहना होगा (उपयोगी होने के लिए), ताकि ऑब्जेक्ट का जीवनकाल एक सिंगलटन का हो।

लेकिन सिंगलटन (एक स्थिर वर्ग / संपत्ति के रूप में सिंगलटन के कम से कम कार्यान्वयन) के साथ समस्या यह है कि इसका उपयोग करने वाले अन्य वर्ग इसे खोजने के बारे में कैसे जाते हैं।

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

यदि हम कक्षा को निर्भरता प्रदान करते हैं , तो यह निर्भरता स्पष्ट है और सभी उपभोग करने वाले वर्ग को इस बात का ज्ञान होना चाहिए कि इसका उपयोग करने के लिए अनुबंध उपलब्ध है।


2
डेटा की एक विशाल राशि है कि कुछ स्क्रीन की आवश्यकता हो सकती है, लेकिन जरूरी नहीं है। और आपको पता नहीं है कि जब तक उपयोगकर्ता कार्रवाई नहीं की गई है जो इसे परिभाषित करते हैं - और कई, कई संयोजन हैं। तो यह जिस तरह से किया गया था वह कुछ सामान्य वैश्विक डेटा था जिसे ग्राहक में कैश और सिंक किया जाता है (ज्यादातर लॉगिन पर प्राप्त होता है), और फिर बाद में अनुरोध कैश को अधिक बनाते हैं, क्योंकि स्पष्ट रूप से अनुरोध किए गए डेटा को फिर से उपयोग में लाया जाता है। एक ही सत्र। सर्वर से अनुरोध करने पर ध्यान केंद्रित किया जाता है, इसलिए क्लाइंट साइड कैश की आवश्यकता होती है। <cont>
बॉबी टेबल्स

1
<cont> यह अनिवार्य रूप से पारदर्शी है। इस अर्थ में कि सर्वर से कॉलबैक है यदि कुछ आवश्यक डेटा को अभी तक कैश नहीं किया गया है। लेकिन उस कैश मैनेजर का कार्यान्वयन (तार्किक और शारीरिक रूप से) एक सिंगलटन है।
बॉबी टेबल्स

6
मैं यहां qstarin के साथ हूं: डेटा तक पहुंचने वाली वस्तुओं को पता नहीं होना चाहिए (या पता करने की आवश्यकता है) कि डेटा कैश है (यह एक कार्यान्वयन विवरण है)। डेटा के उपयोगकर्ता केवल डेटा के लिए पूछते हैं (या डेटा को पुनः प्राप्त करने के लिए इंटरफ़ेस के लिए पूछते हैं)।
मार्टिन

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

2
@ बॉबी टेबल्स: तब आपकी स्थिति उतनी विकट नहीं है जितनी कि यह लग रही थी। वह सिंगलटन (आप एक स्थिर वर्ग का अर्थ है, न कि केवल उदाहरण के साथ एक वस्तु जो कि ऐप के रूप में लंबे समय तक रहता है) अभी भी समस्याग्रस्त है। यह इस तथ्य को छिपा रहा है कि ऑब्जेक्ट प्रदान करने वाले आपके डेटा का कैश प्रदाता पर निर्भरता है। यदि यह स्पष्ट और बाह्य है तो बेहतर है। उन्हें गिरा दो। यह परीक्षणशीलता के लिए आवश्यक है कि आप आसानी से घटकों को प्रतिस्थापित कर सकते हैं, और कैश प्रदाता ऐसे घटक का एक प्रमुख उदाहरण है (कितनी बार कैश प्रदाता ASP.Net द्वारा समर्थित है)।
क्वेंटिन-स्टारिन

45

मैंने इस प्रश्न पर एक पूरा अध्याय लिखा है । अधिकतर खेलों के संदर्भ में, लेकिन इसका अधिकांश हिस्सा खेलों से बाहर होना चाहिए।

tl; डॉ:

द गैंग ऑफ़ फोर सिंग्लटन पैटर्न दो काम करता है: आपको कहीं से भी किसी वस्तु तक सुविधा पहुँच प्रदान करता है, और यह सुनिश्चित करता है कि इसका केवल एक उदाहरण ही बनाया जा सकता है। 99% समय, आप सभी के बारे में परवाह करते हैं कि पहली छमाही है, और दूसरी छमाही के साथ कार्टिंग इसे अनावश्यक सीमा कहते हैं।

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

आप इसे उपयोग कर रहे हैं सिर्फ इसलिए कि आप कोड में स्थानों का उद्देश्य एक ही स्पर्श की जरूरत है कि का एक बहुत है, यह करने के लिए देने के लिए एक बेहतर तरीका खोजने की कोशिश सिर्फ पूरे codebase के संपर्क में लाने के बिना उन वस्तुओं। अन्य उपाय:

  • इसे पूरी तरह से खाई। मैंने बहुत सारे सिंगलटन वर्ग देखे हैं, जिनमें कोई भी राज्य नहीं है और बस सहायक कार्यों के बैग हैं। उन लोगों को एक उदाहरण की जरूरत नहीं है। बस उन्हें स्थिर कार्य करें, या उन्हें उन वर्गों में से एक में स्थानांतरित करें जिन्हें फ़ंक्शन एक तर्क के रूप में लेता है। Mathयदि आपको बस करना हो तो आपको एक विशेष वर्ग की आवश्यकता नहीं होगी 123.Abs()

  • इसे पास करो। यदि किसी विधि को किसी अन्य वस्तु की आवश्यकता होती है तो सरल समाधान बस इसे अंदर पारित करना है। कुछ वस्तुओं को चारों ओर से गुजरने में कुछ भी गलत नहीं है।

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


1
क्या आप यहाँ संक्षेप में बता सकते हैं?
निकोल

1
हो गया, लेकिन मैं अभी भी आपको पूरा अध्याय पढ़ने के लिए प्रोत्साहित करता हूँ।
उदार

4
एक अन्य विकल्प: निर्भरता इंजेक्शन!
ब्रैड कपिट

1
@BradCupit वह इस बारे में लिंक पर भी बात करता है ... मुझे कहना होगा कि मैं अभी भी यह सब पचाने की कोशिश कर रहा हूं। लेकिन यह मैंने कभी पढ़ा है एकल पर सबसे अधिक पढ़ा गया है। अब तक, मैं सकारात्मक एकमात्र जरूरत थी, बस वैश्विक वार्स की तरह था, और मैं था को बढ़ावा देने के साधन । अब मुझे अभी कुछ पता नहीं है। श्री munificient क्या आप मुझे बता सकते हैं अगर सेवा लोकेटर सिर्फ एक है स्थिर टूलबॉक्स ? क्या इसे एकल (इस प्रकार, टूलबॉक्स) बनाना बेहतर नहीं होगा?
क्रैगॉक्स

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

21

इसकी वैश्विक स्थिति प्रति se कि समस्या नहीं है।

वास्तव में आपको केवल चिंतित होने की आवश्यकता है global mutable state। लगातार राज्य प्रभावित नहीं होता है और इस तरह समस्या कम होती है।

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

आपकी स्थिति में मुझे लगता है कि आप इससे दूर हो सकते हैं जब तक कि आपका सिंगलटन वास्तव में एक इंटरफ़ेस लागू करता है (ताकि अन्य स्थितियों में एक विकल्प का उपयोग किया जा सके)।

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

// Example from 5 minutes (con't be too critical)
class ServerFactory
{
    public:
        // By default return a RealServer
        ServerInterface& getServer();

        // Set a non default server:
        void setServer(ServerInterface& server);
};

class ServerInterface { /* define Interface */ };

class RealServer: public ServerInterface {}; // This is a singleton (potentially)

class TestServer: public ServerInterface {}; // This need not be.

यह समझ आता है। इससे मुझे यह भी लगता है कि मैंने कभी भी सिंग्लेटन्स का दुरुपयोग नहीं किया है, लेकिन बस उनमें से किसी भी उपयोग पर संदेह करना शुरू कर दिया है। लेकिन इन बिंदुओं के अनुसार, मैंने किसी भी सीधे-सीधे दुरुपयोग के बारे में नहीं सोचा। :)
बॉबी टेबल्स

2
(आप शायद मतलब दर असल "कहते प्रति" नहीं)
nohat

4
@ क्या: मैं "क्वींस इंग्लिश" का मूल वक्ता हूं और इस प्रकार किसी भी फ्रांसीसी को तब तक अस्वीकार करता हूं जब तक कि हम इसे बेहतर नहीं बनाते (जैसे le weekendउफ़ यह हमारे लिए एक है)। धन्यवाद :-)
मार्टिन यॉर्क

21
प्रति se लैटिन है।
आनन।

2
@ तोप: ठीक है। यह इतना बुरा नहीं है ;-)
मार्टिन

19

फिर क्या? चूंकि किसी ने भी यह नहीं कहा: टूलबॉक्स । यदि आप वैश्विक चर चाहते हैं ।

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

सीधे शब्दों में कहें, एप्लिकेशन का टूलबॉक्स एक सिंगलटन है जो स्वयं को कॉन्फ़िगर करने के लिए या एप्लिकेशन के स्टार्टअप तंत्र को कॉन्फ़िगर करने की अनुमति देने के लिए जिम्मेदार है ...

public class Toolbox {
     private static Toolbox _instance; 

     public static Toolbox Instance {
         get {
             if (_instance == null) {
                 _instance = new Toolbox(); 
             }
             return _instance; 
         }
     }

     protected Toolbox() {
         Initialize(); 
     }

     protected void Initialize() {
         // Your code here
     }

     private MyComponent _myComponent; 

     public MyComponent MyComponent() {
         get {
             return _myComponent(); 
         }
     }
     ... 

     // Optional: standard extension allowing
     // runtime registration of global objects. 
     private Map components; 

     public Object GetComponent (String componentName) {
         return components.Get(componentName); 
     }

     public void RegisterComponent(String componentName, Object component) 
     {
         components.Put(componentName, component); 
     }

     public void DeregisterComponent(String componentName) {
         components.Remove(componentName); 
     }

}

लेकिन अंदाज़ा लगाओ कि क्या है? यह एक सिंगलटन है!

और एक सिंगलटन क्या है?

शायद यहीं से भ्रम शुरू होता है।

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

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

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

मुझे गलत मत समझो!

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

वैसे भी, टूलबॉक्स के अलावा और भी कई सुझाव हैं, और टूलबॉक्स की तरह ही, हर एक का अनुप्रयोग है ...

अन्य विकल्प

  • सबसे अच्छा लेख जो मैंने अभी-अभी एकल के बारे में पढ़ा है वह विकल्प के रूप में सेवा लोकेटर का सुझाव देता है । मेरे लिए यह मूल रूप से एक " स्टेटिक टूलबॉक्स " है, यदि आप करेंगे। दूसरे शब्दों में, सेवा लोकेटर को एक सिंगलटन बनाएं और आपके पास एक टूलबॉक्स है। यह निश्चित रूप से सिंगलटन से बचने के अपने प्रारंभिक सुझाव के खिलाफ जाता है, लेकिन यह केवल सिंगलटन के मुद्दे को लागू करने के लिए है कि यह कैसे उपयोग किया जाता है, अपने आप में पैटर्न नहीं।

  • अन्य लोग विकल्प के रूप में फैक्टरी पैटर्न का सुझाव देते हैं । यह पहला विकल्प था जो मैंने एक सहकर्मी से सुना था और हमने इसे वैश्विक संस्करण के रूप में हमारे उपयोग के लिए जल्दी से समाप्त कर दिया । यह सुनिश्चित है कि इसका उपयोग होता है, लेकिन ऐसा एकल करता है।

उपरोक्त दोनों विकल्प अच्छे विकल्प हैं। लेकिन यह सब आपके उपयोग पर निर्भर करता है।

अब, हर कीमत पर एकल गाने से बचना ही गलत है ...

  • हारून के जवाब का सुझाव है कि कई कारणों से श्रृंखला के लिए कभी भी सिंगलेट्स का उपयोग नहीं करना चाहिए । लेकिन वे सभी कारणों के खिलाफ हैं कि यह कैसे बीमार है और दुरुपयोग किया जाता है, सीधे पैटर्न के खिलाफ नहीं। मैं उन बिंदुओं के बारे में सभी चिंताओं से सहमत हूं, मैं कैसे नहीं कर सकता? मुझे लगता है कि यह भ्रामक है।

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

व्यावहारिक उदाहरण

मैं अक्सर 2 का उपयोग करते हुए देखता हूं, दोनों पक्ष में और एकल के खिलाफ। वेब कैश (मेरा मामला) और लॉग सेवा

लॉगिंग, कुछ बहस करेंगे , एक आदर्श एकल उदाहरण है, क्योंकि, और मैं बोली:

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

हालांकि अन्य लोग यह तर्क देंगे कि लॉग सेवा का विस्तार करना मुश्किल हो जाता है, क्योंकि आपको अंततः यह एहसास होता है कि वास्तव में केवल एक उदाहरण नहीं होना चाहिए।

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


@ जगत् धन्यवाद! मैं सिर्फ सिंगलेट्स का उपयोग करने के बारे में कुछ चेतावनी जोड़ने के उत्तर को संपादित करने में सोच रहा था ... आपकी बोली पूरी तरह से फिट बैठती है!
क्रैगॉक्स

2
खुशी है कि आपको यह पसंद आया। सुनिश्चित नहीं हैं कि अगर यह downvotes बचने में मदद मिलेगी, हालांकि - शायद पाठकों कठिन समय जोड़ने प्रश्न में बाहर रखी ठोस समस्या को इस पोस्ट में किए गए बिंदु, विशेष रूप से की रोशनी में हो रही है बहुत बढ़िया विश्लेषण में पूर्व उत्तर प्रदान
कुटकी

@ जगत् हाँ, मुझे पता था कि यह एक लंबी लड़ाई थी। मुझे उम्मीद है कि समय बताएगा। ;-)
क्रैगॉक्स

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

1
@ कवस: आह, सॉरी - से उलझ गया java.awt.Toolkit। मेरी बात हालांकि समान है: Toolboxएक ही उद्देश्य के साथ सुसंगत वर्ग के बजाय असंबंधित बिट्स और टुकड़ों के हड़पने वाले बैग की तरह लगता है। मेरे लिए अच्छे डिजाइन की तरह नहीं है। (ध्यान दें कि आप जिस लेख का उल्लेख करते हैं वह 2001 से है, निर्भरता इंजेक्शन और डीआई कंटेनरों से पहले आम हो गया था।)
जॉन स्कीट

5

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

प्रत्येक घटक जिसके पास इस "प्रबंधक" के लिए निर्भरता है, अपने सिंगलटन उदाहरण को क्वेरी करके ऐसा करता है। और अगर आप इस तरह के एक घटक के लिए एक इकाई परीक्षण लिखना चाहते हैं तो आपको इस सिंगलटन उदाहरण में डेटा इंजेक्ट करना होगा, जो आसान नहीं हो सकता है।

यदि दूसरी तरफ आपके "मैनेजर" को एक कंस्ट्रक्टर पैरामीटर के माध्यम से आश्रित घटकों में इंजेक्ट किया जाता है, और घटक को प्रबंधक के ठोस प्रकार, केवल एक इंटरफ़ेस, या सार आधार वर्ग का पता नहीं होता है जो प्रबंधक लागू करता है, तो एक इकाई परीक्षण निर्भरता का परीक्षण करने पर प्रबंधक के वैकल्पिक कार्यान्वयन की आपूर्ति कर सकता है।

यदि आप अपने एप्लिकेशन को बनाने वाले घटकों को कॉन्फ़िगर और तत्काल करने के लिए IOC कंटेनरों का उपयोग करते हैं, तो आप आसानी से अपने IOC कंटेनर को "प्रबंधक" का केवल एक उदाहरण बनाने के लिए कॉन्फ़िगर कर सकते हैं, जिससे आप उसी को प्राप्त कर सकते हैं, केवल एक उदाहरण वैश्विक एप्लिकेशन कैश को नियंत्रित करता है। ।

लेकिन अगर आप यूनिट परीक्षणों की परवाह नहीं करते हैं, तो एक सिंगलटन डिजाइन पैटर्न पूरी तरह से ठीक हो सकता है। (लेकिन मैं इसे वैसे भी नहीं करता)


अच्छी तरह से समझाया गया है, यह वह उत्तर है जो
सिंगलेट्स के

4

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

एक मामला जिसमें सिंगलनेट उपयोगी हैं, जब वे एक ऐसी इकाई का प्रतिनिधित्व करते हैं जो वास्तव में अद्वितीय है। अधिकांश वातावरणों में, डेटाबेस अद्वितीय होते हैं, वास्तव में केवल एक ही डेटाबेस होता है। उस डेटाबेस से कनेक्ट करना जटिल हो सकता है क्योंकि इसके लिए कई विशेष प्रकारों के माध्यम से विशेष अनुमति या ट्रैवर्सिंग की आवश्यकता होती है। उस कनेक्शन को एक सिंगलटन में व्यवस्थित करना शायद अकेले इस कारण से बहुत मायने रखता है।

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

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

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


3

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

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


2

सिंगलेट्स एक प्रोग्राम में सर्वेंट ओरिएंटेड आर्किटेक्चर का प्रक्षेपण हैं।

एक एपीआई एक प्रोटोकॉल स्तर पर एक सिंगलटन का एक उदाहरण है। आप ट्विटर, गूगल आदि को अनिवार्य रूप से एकल के माध्यम से एक्सेस करते हैं। तो एक कार्यक्रम के भीतर एकल क्यों खराब हो जाते हैं?

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

सिंगलनेट एक सर्विस एक्सेस पॉइंट हैं। कार्यक्षमता का एक कसकर बंधे पुस्तकालय के लिए सार्वजनिक इंटरफ़ेस जो शायद बहुत परिष्कृत आंतरिक वास्तुकला को छुपाता है।

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

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

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

कुछ इस तरह:

//XxxService.h:
/**
 * Provide singleton wrapper for Xxx object. This wrapper
 * can be autogenerated so is not made part of the object.
 */

#include "Xxx/Xxx.h"


class XxxService
{
    public:
    /**
     * Return a Xxx object as a singleton. The double check
     * singleton algorithm is used. A 0 return means there was
     * an error. Developers should use this as the access point to
     * get the Xxx object.
     *
     * <PRE>
     * @@ #include "Xxx/XxxService.h"
     * @@ Xxx* xxx= XxxService::Singleton();
     * <PRE>
     */

     static Xxx*     Singleton();

     private:
         static Mutex  mProtection;
};


//XxxService.cpp:

#include "Xxx/XxxService.h"                   // class implemented
#include "LockGuard.h"     

// CLASS SCOPE
//
Mutex XxxService::mProtection;

Xxx* XxxService::Singleton()
{
    static Xxx* singleton;  // the variable holding the singleton

    // First check to see if the singleton has been created.
    //
    if (singleton == 0)
    {
        // Block all but the first creator.
        //
        LockGuard lock(mProtection);

        // Check again just in case someone had created it
        // while we were blocked.
        //
        if (singleton == 0)
        {
            // Create the singleton Xxx object. It's assigned
            // to a temporary so other accessors don't see
            // the singleton as created before it really is.
            //
            Xxx* inprocess_singleton= new Xxx;

            // Move the singleton to state online so we know that is has
            // been created and it ready for use.
            //
            if (inprocess_singleton->MoveOnline())
            {
                LOG(0, "XxxService:Service: FAIL MoveOnline");
                return 0;
            }

            // Wait until the module says it's in online state.
            //
            if (inprocess_singleton->WaitTil(Module::MODULE_STATE_ONLINE))
            {
                LOG(0, "XxxService:Service: FAIL move to online");
                return 0;
            }

            // The singleton is created successfully so assign it.
            //
            singleton= inprocess_singleton;


        }// still not created
    }// not created

    // Return the created singleton.
    //
    return singleton;

}// Singleton  

1

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

आपके पास जो कुछ भी होगा, वह उस वर्ग के पास होगा, लेकिन सभी सांख्यिकी सदस्यों को प्राप्त होगा। ठीक है, यह नहीं है, लेकिन मैं इसे सुझाता हूं। वास्तव में आप केवल एक सामान्य वर्ग की तरह क्लास को इनिशियलाइज़ करते हैं और पॉइंटर को पॉइंटर में डालते हैं। फ़्रीगेन को ClassIWant.trtr () नहीं कहें। LetMeChange.ANYTHINGATALL ()। Andhave_no_structure ()।

इसके अधिक काम लेकिन वास्तव में, इसके कम भ्रामक हैं। कुछ ऐसी जगहें जहाँ आपको ऐसी चीज़ें नहीं बदलनी चाहिए जो अब आपके वैश्विक नहीं हैं। मेरे सभी प्रबंधक वर्ग नियमित कक्षाएं हैं, बस इसे ही मानें।


1

IMO, आपका उदाहरण ठीक लगता है। मैं निम्नानुसार फैक्टरिंग करना चाहूंगा: प्रत्येक के लिए कैश ऑब्जेक्ट (और प्रत्येक के पीछे) डेटा ऑब्जेक्ट; कैश ऑब्जेक्ट और db एक्सेसर ऑब्जेक्ट में एक ही इंटरफ़ेस होता है। यह कोड के अंदर और बाहर कैश स्वैप करने की क्षमता देता है; प्लस यह एक आसान विस्तार मार्ग देता है।

ग्राफिक:

DB
|
DB Accessor for OBJ A
| 
Cache for OBJ A
|
OBJ A Client requesting

DB accessor और cache एक ही ऑब्जेक्ट या duck टाइप से इनहेरिट कर सकते हैं, एक ही ऑब्जेक्ट की तरह, जो भी हो। जब तक आप प्लग / कंपाइल / टेस्ट कर सकते हैं और यह अभी भी काम करता है।

इससे चीजें खराब हो जाती हैं, ताकि आप बिना उबर-कैश ऑब्जेक्ट को संशोधित किए और नए कैश को जोड़ सकें। YMMV। IANAL। आदि।


1

पार्टी के लिए थोड़ा देर से, लेकिन वैसे भी।

सिंगलटन टूलबॉक्स में एक उपकरण है, जैसे कुछ और। उम्मीद है कि आपके टूलबॉक्स में आपके पास सिर्फ एक हथौड़े की तुलना में अधिक है।

इस पर विचार करो:

public void DoSomething()
{
    MySingleton.Instance.Work();
}

बनाम

public void DoSomething(MySingleton singleton)
{
    singleton.Work();
}
DoSomething(MySingleton.instance);

1 मामला उच्च युग्मन आदि की ओर जाता है; 2 तरीके से कोई समस्या नहीं है @Aaronaught वर्णन कर रहा है, जहाँ तक मैं बता सकता हूँ। आप इसका उपयोग कैसे करते हैं, इसके बारे में।


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

कभी-कभी डि किसी दिए गए कार्य के लिए एक ओवरकिल होता है। एक नमूना कोड में विधि एक कंस्ट्रक्टर हो सकती है, लेकिन जरूरी नहीं है - ठोस उदाहरण को देखे बिना एक मूट तर्क। इसके अलावा, DoSomething ISomething ले सकता है, और MySingleton उस इंटरफ़ेस को लागू कर सकता है - ठीक है, यह एक नमूने में नहीं है .. लेकिन इसका सिर्फ एक नमूना है।
इवगेनी

1

प्रत्येक स्क्रीन को प्रबंधक अपने कंस्ट्रक्टर में ले जाएं।

जब आप अपना ऐप शुरू करते हैं, तो आप प्रबंधक का एक उदाहरण बनाते हैं और इसे पास करते हैं।

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

इसलिए अपने ऐप को एक पेड़ की तरह बनाएं, जहाँ ऊपर की चीजें उनके नीचे इस्तेमाल होने वाली हर चीज का मालिक हो। एक जाल की तरह एक ऐप को लागू न करें, जहां हर कोई हर किसी को जानता है और वैश्विक तरीकों के माध्यम से एक-दूसरे को ढूंढता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.