एक Enum (जावा में) के साथ सिंगलटन को लागू करना


178

मैंने पढ़ा है कि Singletonजावा में लागू करना संभव है Enumजैसे कि:

public enum MySingleton {
     INSTANCE;   
}

लेकिन, ऊपर कैसे काम करता है? विशेष रूप से, Objectतत्काल किया जाना है। यहाँ, कैसे MySingletonत्वरित किया जा रहा है? कौन क्या कर रहा है new MySingleton()?


24
कौन नया MySingleton कर रहा है () JVM है
सोतिरियोस डेलिमोलिसिन

37
INSTANCEरूप में ही है public static final MySingleton INSTANCE = new MySingleton();
सायमो

6
ENUM - एक गारंटी वाला सिंगलटन।
एक बग

Dzone.com/articles/java-singletons-use-enum पढ़ें , एनम का उपयोग क्यों करें और अन्य तरीके नहीं। लघुकरण: क्रमांकन और प्रतिबिंब का उपयोग करते समय समस्याएं शुरू होती हैं।
मियागी

जवाबों:


203

यह,

public enum MySingleton {
  INSTANCE;   
}

एक खाली निर्माता है। इसके बजाय इसे स्पष्ट करें,

public enum MySingleton {
    INSTANCE;
    private MySingleton() {
        System.out.println("Here");
    }
}

यदि आपने फिर एक अन्य वर्ग को एक main()विधि के साथ जोड़ा

public static void main(String[] args) {
    System.out.println(MySingleton.INSTANCE);
}

तुम देखोगे

Here
INSTANCE

enumफ़ील्ड संकलित समय संकलित हैं, लेकिन वे उनके enumप्रकार के उदाहरण हैं । और, वे निर्माण किए जाते हैं जब पहली बार एनम प्रकार संदर्भित होता है ।


13
आपको यह जोड़ना चाहिए कि डिफ़ॉल्ट एनमों में निहित निजी कंस्ट्रक्टर है और यह स्पष्ट रूप से एक निजी कंस्ट्रक्टर को जोड़ने की आवश्यकता नहीं है, जब तक कि आपके पास वास्तव में उस कोड को चलाने की आवश्यकता नहीं है
निमरोड दयाण

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

2
सार्वजनिक रूप से MySingleton {INSTANCE, INSTANCE 1; } और उसके बाद System.out.println (MySingleton.INSTANCE.hashCode ()); Println (MySingleton.INSTANCE1.hashCode ()); यह अलग-अलग हैशकोड प्रिंट करता है। क्या इसका मतलब है कि MySingleton की दो वस्तुएँ बनी हैं?
स्कॉटलैंड मील

@scottmiles हाँ। क्योंकि आपके पास दो उदाहरण हैं। एक सिंगलटन, परिभाषा के अनुसार, एक है।
इलियट फ्रिस्क

privateसंशोधक के लिए कोई मतलब नहीं है enumनिर्माता और पूरी तरह अनावश्यक है।
दिमित्री नेस्टरुक

76

एक enumप्रकार एक विशेष प्रकार का है class

आपका enumवास्तव में ऐसा कुछ करने के लिए संकलित किया जाएगा

public final class MySingleton {
    public final static MySingleton INSTANCE = new MySingleton();
    private MySingleton(){} 
}

जब आपका कोड पहली बार एक्सेस करता है INSTANCE, तो क्लास MySingletonको JVM द्वारा लोड और इनिशियलाइज़ किया जाएगा। यह प्रक्रिया एक बार (लैज़ी) से staticऊपर के क्षेत्र को आरंभ करती है ।


क्या इस वर्ग में निजी कंस्ट्रक्टर () भी होंगे? मुझे लगता है कि यह होगा
यासिर शब्बीर चौधरी

public enum MySingleton { INSTANCE,INSTANCE1; }और फिर System.out.println(MySingleton.INSTANCE.hashCode()); System.out.println(MySingleton.INSTANCE1.hashCode());यह अलग-अलग हैशकोड प्रिंट करता है। क्या इसका मतलब है कि MySingleton की दो वस्तुएँ बनी हैं?
स्कूट मील

2
@scottmiles हाँ, यह सिर्फ दो अंतर enumस्थिरांक है।
सोटिरिओस डेलिमोनोलिस


@SotiriosDelimanolis, क्या यह एनम थ्रेड सुरक्षित है?
एबीजी

63

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

एक वर्ग को सिंग्लटन बनाना अपने ग्राहकों का परीक्षण करना मुश्किल बना सकता है, क्योंकि एक सिंगलटन के लिए एक नकली कार्यान्वयन को प्रतिस्थापित करना असंभव है जब तक कि यह एक इंटरफ़ेस को लागू नहीं करता है जो इसके प्रकार के रूप में कार्य करता है। अनुशंसित दृष्टिकोण सिंगलेट्स को केवल एक तत्व के साथ एक एनुम प्रकार लागू करने के लिए है:

// Enum singleton - the preferred approach
public enum Elvis {
INSTANCE;
public void leaveTheBuilding() { ... }
}

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

हालांकि इस दृष्टिकोण को व्यापक रूप से अपनाया जाना बाकी है, एकल-तत्व एनम प्रकार एक सिंगलटन को लागू करने का सबसे अच्छा तरीका है।


मुझे लगता है, एक सिंगलटन को परीक्षण योग्य बनाने के लिए आप एक रणनीति पैटर्न का उपयोग कर सकते हैं और सभी सिंगलटन के कार्यों को रणनीति के माध्यम से जाना होगा। तो आपके पास एक "उत्पादन" रणनीति और एक "परीक्षण" रणनीति हो सकती है ...
Erk

9

सभी enum उदाहरणों की तरह, Java प्रत्येक ऑब्जेक्ट को क्लास लोड होने पर, कुछ गारंटी के साथ बताता है कि यह तुरंत एक बार प्रति VVM हैINSTANCEसार्वजनिक स्थैतिक अंतिम क्षेत्र के रूप में घोषणा के बारे में सोचो : जावा पहली बार जिस कक्षा को संदर्भित करता है, उस वस्तु को तुरंत हटा देगा।

उदाहरण स्थैतिक आरंभीकरण के दौरान बनाए जाते हैं, जिसे जावा भाषा विनिर्देश, खंड 12.4 में परिभाषित किया गया है ।

जोश के लायक है, यहोशू बलोच ने प्रभावी जावा द्वितीय संस्करण के आइटम 3 के रूप में इस पैटर्न का विस्तार से वर्णन किया है ।


6

चूंकि सिंगलटन पैटर्न एक निजी कंस्ट्रक्टर है और कुछ तरीकों (जैसे कुछ getInstance) को नियंत्रित करने के लिए कुछ तरीके से कॉल कर रहा है, एनम में हमारे पास पहले से ही एक निहित निजी कंस्ट्रक्टर है।

मुझे ठीक से पता नहीं है कि जेवीएम या कुछ कंटेनर हमारे उदाहरणों को कैसे नियंत्रित करते हैं Enums, लेकिन ऐसा लगता है कि यह पहले से ही एक निहितार्थ का उपयोग करता है Singleton Pattern, अंतर यह है कि हम कॉल नहीं करते हैं getInstance, हम सिर्फ एनम कहते हैं।


3

जैसा कि कुछ हद तक पहले उल्लेख किया गया है, एक एनम एक जावा वर्ग है जिसकी विशेष स्थिति है कि इसकी परिभाषा कम से कम एक "एनम निरंतर" के साथ शुरू होनी चाहिए।

इसके अलावा, और उस एनम कैंट को बढ़ाया नहीं जा सकता है या अन्य वर्गों को विस्तारित करने के लिए उपयोग किया जाता है, एक एनम किसी भी वर्ग की तरह एक वर्ग है और आप इसे निरंतर परिभाषाओं के नीचे के तरीकों को जोड़कर उपयोग करते हैं:

public enum MySingleton {
    INSTANCE;

    public void doSomething() { ... }

    public synchronized String getSomething() { return something; }

    private String something;
}

आप इन लाइनों के साथ सिंगलटन के तरीकों का उपयोग करते हैं:

MySingleton.INSTANCE.doSomething();
String something = MySingleton.INSTANCE.getSomething();

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

और, शायद, सबसे महत्वपूर्ण बात यह है कि इस व्यवहार की गारंटी खुद जेवीएम और जावा विनिर्देशन ने दी है।

यहाँ पर जावा विनिर्देशन से एक अनुभाग है कि एनुम इंस्टेंस के कई उदाहरणों को कैसे रोका जाता है:

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

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

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