जावा में तर्क के साथ सिंगलटन


142

मैं विकिपीडिया पर सिंगलटन लेख पढ़ रहा था और मैं इस उदाहरण पर आया:

public class Singleton {
    // Private constructor prevents instantiation from other classes
    private Singleton() {}

    /**
     * SingletonHolder is loaded on the first execution of Singleton.getInstance() 
     * or the first access to SingletonHolder.INSTANCE, not before.
     */
    private static class SingletonHolder { 
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

जबकि मैं वास्तव में जिस तरह से इस सिंगलटन का व्यवहार करता हूं, मैं यह नहीं देख सकता कि इसे कंस्ट्रक्टर को तर्कों को शामिल करने के लिए कैसे अनुकूलित किया जाए। जावा में ऐसा करने का पसंदीदा तरीका क्या है? क्या मुझे ऐसा कुछ करना होगा?

public class Singleton
{
    private static Singleton singleton = null;  
    private final int x;

    private Singleton(int x) {
        this.x = x;
    }

    public synchronized static Singleton getInstance(int x) {
        if(singleton == null) singleton = new Singleton(x);
        return singleton;
    }
}

धन्यवाद!


संपादित करें: मुझे लगता है कि मैंने सिंगलटन का उपयोग करने की इच्छा के साथ विवाद की आंधी शुरू कर दी है। मुझे अपनी प्रेरणा समझाएं और उम्मीद है कि कोई बेहतर विचार सुझा सकता है। मैं समानांतर में कार्यों को निष्पादित करने के लिए एक ग्रिड कंप्यूटिंग ढांचे का उपयोग कर रहा हूं। सामान्य तौर पर, मेरे पास ऐसा कुछ है:

// AbstractTask implements Serializable
public class Task extends AbstractTask
{
    private final ReferenceToReallyBigObject object;

    public Task(ReferenceToReallyBigObject object)
    {
        this.object = object;
    }

    public void run()
    {
        // Do some stuff with the object (which is immutable).
    }
}

क्या होता है कि भले ही मैं केवल अपने डेटा के सभी कार्यों के लिए एक संदर्भ देता हूं, जब कार्यों को क्रमबद्ध किया जाता है, तो डेटा को बार-बार कॉपी किया जाता है। मैं जो करना चाहता हूं वह सभी कार्यों के बीच वस्तु को साझा करना है। स्वाभाविक रूप से, मैं कक्षा को इस तरह संशोधित कर सकता हूं:

// AbstractTask implements Serializable
public class Task extends AbstractTask
{
    private static ReferenceToReallyBigObject object = null;

    private final String filePath;

    public Task(String filePath)
    {
        this.filePath = filePath;
    }

    public void run()
    {
        synchronized(this)
        {
            if(object == null)
            {
                ObjectReader reader = new ObjectReader(filePath);
                object = reader.read();
            }
        }

        // Do some stuff with the object (which is immutable).
    }
}

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


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

2
यह काफी दुर्भाग्यपूर्ण है कि आपने सिंगलटन शब्द का इस्तेमाल किया जो इस तरह के सामान के साथ आता है। इस पैटर्न के लिए उचित शब्द वास्तव में इंटर्निंग है। इंटर्निंग यह सुनिश्चित करने की एक विधि है कि अमूर्त मूल्यों को केवल एक उदाहरण द्वारा दर्शाया जाता है। स्ट्रिंग इंटर्निंग सबसे आम उपयोग है: en.wikipedia.org/wiki/String_intern_pool।
27'09

आप टेराकोटा पर एक नज़र रखना चाह सकते हैं। यह क्लस्टर भर में ऑब्जेक्ट की पहचान बनाए रखता है। जब आप क्लस्टर में पहले से ही डेटा का संदर्भ भेजते हैं तो यह पुन: क्रमबद्ध नहीं होता है।
टेलर गॉटियर

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

2
"मापदंडों के साथ सिंगलटन" के लिए एक और परिदृश्य: एक वेब एप्लिकेशन जो बहुत पहले आने वाले अनुरोध (थ्रेड) के साथ आने वाले informations के आधार पर अपने अद्वितीय अपरिवर्तनीय सिंगलटन का निर्माण करेगा। अनुरोध का डोमेन उदाहरण के लिए कुछ सिंगलटन के व्यवहार को निर्धारित कर सकता है
फस्टाकी

जवाबों:


171

मैं अपनी बात बहुत स्पष्ट करूँगा: एक सिंगलटन मापदंडों के साथ एक सिंगलटन नहीं है

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

आपके पास दो विकल्प हैं। यदि आप चाहते हैं कि आपकी सिंगलटन को कुछ डेटा के साथ आरंभीकृत किया जाए, तो आप इसे इंस्टेंटेशन के बाद डेटा के साथ लोड कर सकते हैं , जैसे:

SingletonObj singleton = SingletonObj.getInstance();
singleton.init(paramA, paramB); // init the object with data

यदि आपका सिंगलटन जिस ऑपरेशन को कर रहा है वह आवर्ती है, और हर बार अलग-अलग मापदंडों के साथ, आप मापदंडों को निष्पादित किए जा रहे मुख्य विधि में पास कर सकते हैं:

SingletonObj singleton = SingletonObj.getInstance();
singleton.doSomething(paramA, paramB); // pass parameters on execution

किसी भी मामले में, तात्कालिकता हमेशा पैरामीटर-कम होगी। अन्यथा आपका सिंगलटन एक सिंगलटन नहीं है।


1
+1 यह है कि कोडिंग करते समय मैं इसे कैसे करूँगा। C # में, मैं अभी संपत्तियों का उपयोग करूंगा। जावा, शायद इस तरह।
जक

131
क्षमा करें, यह सच नहीं है। ऐसी परिस्थितियां हैं जहां आपको गतिशील रूप से बनाए गए मापदंडों में पास होना पड़ता है जो कि होल एप्लिकेशन रनटाइम के लिए समान रहते हैं। इसलिए आप सिंगलटन के भीतर एक कंटीन्यू का उपयोग नहीं कर सकते, लेकिन इसके बनने पर उस कंटीन्यू को पास करना होगा। छेद के समय के लिए एक ही निरंतर के बाद पारित कर दिया। यदि आपको कंस्ट्रक्टर के भीतर उस विशिष्ट स्थिरांक की आवश्यकता है तो एक सेटर काम नहीं करेगा।
मासी

1
@masi, जैसा कि लेखक कहता है - यह एक सिंगलटन नहीं है। यदि आपको निरंतर गतिशीलता को पारित करने की आवश्यकता है, तो आपको विभिन्न स्थिरांक के साथ बहुत सी कक्षाएं बनाने की आवश्यकता हो सकती है। तो, सिंगलटन का कोई मतलब नहीं है।
दिमित्री ज़ेत्सेव

53
यदि आपको किसी एप्लिकेशन के पूरे जीवनकाल के लिए केवल एक वर्ग की आवश्यकता है, लेकिन आपको लॉन्च समय पर एक मूल्य के साथ उस उदाहरण को प्रदान करने की आवश्यकता है, तो यह अब एकल क्यों नहीं है?
ऑस्कर

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

41

मुझे लगता है कि आपको एक कारखाने की तरह कुछ चाहिए जो विभिन्न मापदंडों के साथ वस्तुओं को तात्कालिक और पुन: उपयोग में लाए। यह आपके 'सिंगलटन' के पैरामीटर योग्य वर्ग के लिए एक सिंक्रनाइज़ ( HashMapया एक उदाहरण के लिए) ConcurrentHashMapपैरामीटर का उपयोग करके लागू किया जा सकता है Integer

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

इस तरह की दुकान के लिए एक उदाहरण है:

public final class UsefulObjFactory {

    private static Map<Integer, UsefulObj> store =
        new HashMap<Integer, UsefulObj>();

    public static final class UsefulObj {
        private UsefulObj(int parameter) {
            // init
        }
        public void someUsefulMethod() {
            // some useful operation
        }
    }

    public static UsefulObj get(int parameter) {
        synchronized (store) {
            UsefulObj result = store.get(parameter);
            if (result == null) {
                result = new UsefulObj(parameter);
                store.put(parameter, result);
            }
            return result;
        }
    }
}

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

हालांकि, यदि आपको वितरित 1 समाधान की आवश्यकता है, तो कुछ पार्श्व कैशिंग समाधान पर विचार करें। उदाहरण के लिए: EHCache, टेराकोटा, आदि।

1 शायद कई कंप्यूटरों पर कई वीएम फैलाने के अर्थ में।


हां, यह वही है जो मुझे चाहिए। आपका बहुत बहुत धन्यवाद! मैं मानता हूं कि जिस तरह से मैं अपने उदाहरण में तर्क दे रहा था, उससे बहुत मतलब नहीं था, लेकिन मैंने ऐसा नहीं सोचा था। Oxbow_lakes 'के उत्तर की टिप्पणियों में मेरी व्याख्या देखें।

1
यह एक सिंगलटन नहीं है; अब आपके पास उनमें से एक से अधिक है। LOL
oxbow_lakes

@ स्थिति: मैं कुछ सुझाव दूंगा जैसे युवल ने नीचे सुझाया था। यह थोड़ा अधिक समझ में आता है और आपके पास एक 'सच्चा' सिंगलटन है। संपादित करें
Zack

मुझे आशा है कि कोई भी मुझे कोड में नाम संपादित करने में कोई दिमाग नहीं लगाएगा; मैं कल्पना कर सकता हूँ कि यह वास्तव में newbies के लिए भ्रामक है। अगर आप असहमत हैं तो रोलबैक करें
oxbow_lakes

हां, हम उन्हें मल्टीट्रॉन कह सकते हैं और अभी भी उसी लक्ष्य को प्राप्त कर सकते हैं जो ओपी पहले स्थान पर आईएमएचओ में चाहता था।
एकरनोकड

22

प्राप्त करने से तात्कालिकता को अलग करने के लिए आप एक विन्यास योग्य आरंभ विधि जोड़ सकते हैं।

public class Singleton {
    private static Singleton singleton = null;
    private final int x;

    private Singleton(int x) {
        this.x = x;
    }

    public static Singleton getInstance() {
        if(singleton == null) {
            throw new AssertionError("You have to call init first");
        }

        return singleton;
    }

    public synchronized static Singleton init(int x) {
        if (singleton != null)
        {
            // in my opinion this is optional, but for the purists it ensures
            // that you only ever get the same instance when you call getInstance
            throw new AssertionError("You already initialized me");
        }

        singleton = new Singleton(x);
        return singleton;
    }

}

फिर आप Singleton.init(123)इसे कॉन्फ़िगर करने के लिए एक बार कॉल कर सकते हैं , उदाहरण के लिए अपने ऐप स्टार्टअप में।


13

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

    public enum EnumSingleton {

    INSTANCE;

    private String name; // Mandatory
    private Double age = null; // Not Mandatory

    private void build(SingletonBuilder builder) {
        this.name = builder.name;
        this.age = builder.age;
    }

    // Static getter
    public static EnumSingleton getSingleton() {
        return INSTANCE;
    }

    public void print() {
        System.out.println("Name "+name + ", age: "+age);
    }


    public static class SingletonBuilder {

        private final String name; // Mandatory
        private Double age = null; // Not Mandatory

        private SingletonBuilder(){
          name = null;
        }

        SingletonBuilder(String name) {
            this.name = name;
        }

        public SingletonBuilder age(double age) {
            this.age = age;
            return this;
        }

        public void build(){
            EnumSingleton.INSTANCE.build(this);
        }

    }


}

तब आप इसे फॉलो / क्रिएट / पैराट्राइज्ड बना सकते हैं :

public static void main(String[] args) {
    new EnumSingleton.SingletonBuilder("nico").age(41).build();
    EnumSingleton.getSingleton().print();
}

6

" मापदंडों के साथ एक सिंगलटन एक सिंगलटन नहीं है " कथन पूरी तरह से सही नहीं है । हमें कोड परिप्रेक्ष्य के बजाय एप्लिकेशन परिप्रेक्ष्य से इसका विश्लेषण करने की आवश्यकता है।

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

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


12
यह ओपी प्रश्न का उत्तर नहीं है, यह एक टिप्पणी होनी चाहिए।
थियरी जे।

5

चर सेट करने के लिए गेटर्स और सेटर का उपयोग करें और डिफ़ॉल्ट कंस्ट्रक्टर को निजी बनाएं। फिर उपयोग करें:

Singleton.getInstance().setX(value);

1
मत जाओ कि यह मतदान क्यों हुआ .. यह एक मान्य उत्तर है। : /
ज़ैक

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

5

हैरानी हुई कि किसी ने यह नहीं बताया कि एक लकड़हारा कैसे बना / पुनर्प्राप्त किया गया। उदाहरण के लिए, नीचे दिखाया गया है कि Log4J लकड़हारा कैसे पुनर्प्राप्त किया जाता है।

// Retrieve a logger named according to the value of the name parameter. If the named logger already exists, then the existing instance will be returned. Otherwise, a new instance is created.
public static Logger getLogger(String name)

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

69   Hashtable ht;
...
258  public
259  Logger getLogger(String name, LoggerFactory factory) {
260    //System.out.println("getInstance("+name+") called.");
261    CategoryKey key = new CategoryKey(name);
262    // Synchronize to prevent write conflicts. Read conflicts (in
263    // getChainedLevel method) are possible only if variable
264    // assignments are non-atomic.
265    Logger logger;
266
267    synchronized(ht) {
268      Object o = ht.get(key);
269      if(o == null) {
270        logger = factory.makeNewLoggerInstance(name);
271        logger.setHierarchy(this);
272        ht.put(key, logger);
273        updateParents(logger);
274        return logger;
275      } else if(o instanceof Logger) {
276        return (Logger) o;
277      } 
...

4

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

public final class RInterfaceHL {

    /**
     * Private constructor prevents instantiation from other classes.
     */
    private RInterfaceHL() { }

    /**
     * R REPL (read-evaluate-parse loop) handler.
     */
    private static RMainLoopCallbacks rloopHandler = null;

    /**
     * SingletonHolder is loaded, and the static initializer executed, 
     * on the first execution of Singleton.getInstance() or the first 
     * access to SingletonHolder.INSTANCE, not before.
     */
    private static final class SingletonHolder {

        /**
         * Singleton instance, with static initializer.
         */
        private static final RInterfaceHL INSTANCE = initRInterfaceHL();

        /**
         * Initialize RInterfaceHL singleton instance using rLoopHandler from
         * outer class.
         * 
         * @return RInterfaceHL instance
         */
        private static RInterfaceHL initRInterfaceHL() {
            try {
                return new RInterfaceHL(rloopHandler);
            } catch (REngineException e) {
                // a static initializer cannot throw exceptions
                // but it can throw an ExceptionInInitializerError
                throw new ExceptionInInitializerError(e);
            }
        }

        /**
         * Prevent instantiation.
         */
        private SingletonHolder() {
        }

        /**
         * Get singleton RInterfaceHL.
         * 
         * @return RInterfaceHL singleton.
         */
        public static RInterfaceHL getInstance() {
            return SingletonHolder.INSTANCE;
        }

    }

    /**
     * Return the singleton instance of RInterfaceHL. Only the first call to
     * this will establish the rloopHandler.
     * 
     * @param rloopHandler
     *            R REPL handler supplied by client.
     * @return RInterfaceHL singleton instance
     * @throws REngineException
     *             if REngine cannot be created
     */
    public static RInterfaceHL getInstance(RMainLoopCallbacks rloopHandler)
            throws REngineException {
        RInterfaceHL.rloopHandler = rloopHandler;

        RInterfaceHL instance = null;

        try {
            instance = SingletonHolder.getInstance();
        } catch (ExceptionInInitializerError e) {

            // rethrow exception that occurred in the initializer
            // so our caller can deal with it
            Throwable exceptionInInit = e.getCause();
            throw new REngineException(null, exceptionInInit.getMessage());
        }

        return instance;
    }

    /**
     * org.rosuda.REngine.REngine high level R interface.
     */
    private REngine rosudaEngine = null;

    /**
     * Construct new RInterfaceHL. Only ever gets called once by
     * {@link SingletonHolder.initRInterfaceHL}.
     * 
     * @param rloopHandler
     *            R REPL handler supplied by client.
     * @throws REngineException
     *             if R cannot be loaded.
     */
    private RInterfaceHL(RMainLoopCallbacks rloopHandler)
            throws REngineException {

        // tell Rengine code not to die if it can't
        // load the JRI native DLLs. This allows
        // us to catch the UnsatisfiedLinkError
        // ourselves
        System.setProperty("jri.ignore.ule", "yes");

        rosudaEngine = new JRIEngine(new String[] { "--no-save" }, rloopHandler);
    }
}

मुझे लगता है कि यह एक अच्छा विचार हो सकता है finally { RInterfaceHL.rloopHandler = null; }में getInstance, क्योंकि वह स्थिर संदर्भ एक स्मृति रिसाव का कारण हो सकता है अगर हम सावधान नहीं कर रहे हैं। आपके मामले में ऐसा लग रहा है कि यह कोई मुद्दा नहीं है, लेकिन मैं एक ऐसे परिदृश्य की कल्पना कर सकता हूं जहां पारित वस्तु बड़ी है और केवल RInterfaceHLकुछ मूल्यों को प्राप्त करने के लिए ctor द्वारा उपयोग किया जाता है , न कि इसका संदर्भ रखने के लिए।
ट्वीस्टेरोब

विचार: return SingletonHolder.INSTANCEबस के रूप में ठीक काम करेगा getInstance। मुझे नहीं लगता कि यहां एनकैप्सुलेशन की आवश्यकता है, क्योंकि बाहरी वर्ग पहले से ही आंतरिक वर्ग के अंतर को जानता है, वे कसकर युग्मित हैं: यह rloopHandlerकॉल करने से पहले इनिट की जरूरत जानता है । इसके अलावा निजी निर्माणकर्ता पर कोई प्रभाव नहीं पड़ता है, क्योंकि आंतरिक वर्ग का निजी सामान केवल बाहरी वर्ग के लिए उपलब्ध है।
ट्वीस्टेरोब

1
लिंक टूट गया है। क्या आप en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom का उल्लेख कर रहे थे ?
जॉर्ज लविन

3

जिस कारण से आप यह समझ नहीं पा रहे हैं कि आप जो करने की कोशिश कर रहे हैं, वह कैसे संभव है कि आप जो करने की कोशिश कर रहे हैं वह वास्तव में समझ में नहीं आता। आप getInstance(x)विभिन्न तर्कों के साथ कॉल करना चाहते हैं , लेकिन हमेशा एक ही वस्तु को लौटाते हैं? जब आप कॉल करते हैं getInstance(2)और तब आप क्या व्यवहार चाहते हैं getInstance(5)?

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

यदि आप चाहते हैं getInstance(2)और getInstance(5)विभिन्न वस्तुओं को वापस करने के लिए, दूसरी ओर, आप सिंगलटन पैटर्न का उपयोग नहीं कर रहे हैं, तो आप फैक्टरी पैटर्न का उपयोग कर रहे हैं।


3

अपने उदाहरण में आप एक सिंगलटन का उपयोग नहीं कर रहे हैं। ध्यान दें कि यदि आप निम्नलिखित करते हैं (यह मानते हुए कि Singleton.getInstance वास्तव में स्थिर था):

Singleton obj1 = Singleton.getInstance(3);
Singleton obj2 = Singleton.getInstance(4);

तब obj2.x का मान 3 है, 4 नहीं। यदि आपको ऐसा करने की आवश्यकता है, तो इसे एक सादा वर्ग बनाएं। यदि मानों की संख्या छोटी और निश्चित है, तो आप a का उपयोग करने पर विचार कर सकते हैंenum । यदि आपको अत्यधिक ऑब्जेक्ट पीढ़ी (जो आमतौर पर मामला नहीं है) के साथ समस्या हो रही है, तो आप कैशिंग मानों पर विचार कर सकते हैं (और स्रोतों की जांच करें या इसके साथ सहायता प्राप्त करें, क्योंकि यह स्पष्ट है कि मेमोरी लीक के खतरे के बिना कैश कैसे बनाया जाए)।

आप इस लेख को भी पढ़ना चाह सकते हैं क्योंकि सिंगलेट्स को बहुत आसानी से इस्तेमाल किया जा सकता है।


3

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


3

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

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


1

यह काफी एकल नहीं है, लेकिन ऐसा कुछ हो सकता है जो आपकी समस्या को ठीक कर सकता है।

public class KamilManager {

  private static KamilManager sharedInstance;

  /**
   * This method cannot be called before calling KamilManager constructor or else
   * it will bomb out.
   * @return
   */
  public static KamilManager getInstanceAfterInitialized() {
    if(sharedInstance == null)
        throw new RuntimeException("You must instantiate KamilManager once, before calling this method");

    return sharedInstance;
}

  public KamilManager(Context context, KamilConfig KamilConfig) {
    //Set whatever you need to set here then call:
  s  haredInstance = this;
  }
}

1

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

एक और सवाल है: क्या राज्य के साथ सिंगलटन होना अच्छा है?


1

क्या हम ऐसा कुछ नहीं कर सकते:

public class Singleton {

    private int x;

    // Private constructor prevents instantiation from other classes
    private Singleton() {}

    /**
     * SingletonHolder is loaded on the first execution of Singleton.getInstance() 
     * or the first access to SingletonHolder.INSTANCE, not before.
     */
    private static class SingletonHolder { 
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance(int x) {
        Singleton instance = SingletonHolder.INSTANCE;
        instance.x = x;
        return instance;
    }
}

1

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

public class Singleton {

    private static String aParameterStored;

    private static final Singleton instance = new Singleton("Param to set");

    private Singleton() {
        // do nothing
    }

    private Singleton(String param) {
        aParameterStored = param;
    }

    public static Singleton getInstance() {
        return instance;
    }

    /*
     * ... stuff you would like the singleton do
     */
}

सिंगलटन पैटर्न कहता है:

  • सुनिश्चित करें कि एकल वर्ग का केवल एक उदाहरण कभी मौजूद है
  • उस उदाहरण के लिए वैश्विक पहुँच प्रदान करें।

जो इस उदाहरण के साथ सम्मानित हैं।

सीधे प्रॉपर्टी को सेट क्यों नहीं किया? यह दिखाने के लिए पाठ्यपुस्तक का मामला है कि हम कैसे एक सिंगलटन को पैरामीटर के साथ कंस्ट्रक्टर कर सकते हैं लेकिन यह कुछ स्थितियों में उपयोगी हो सकता है। उदाहरण के लिए विरासत के मामलों में सिंगलटन को कुछ सुपरक्लास गुण सेट करने के लिए मजबूर करने के लिए।


0

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

public class example  {
    private volatile static example instance;

    private String string;
    private int iInt = -1; //any number you know you don't want to use here

  private example() {

    //In case someone uses the private method to create a new Instance
    if (instance != null){
      throw new RuntimeException("Use getInstance() method to get the single instance of this class.");
    }
  }

  public synchronized static example getIsntance(){
    if(instance == null){
      instance = new example();
    }
    return instance;
  }

public void methodDoingWork(){
    if(checkInit()){
      //DoSome
    }
  }

  private boolean checkInit(){
    boolean filled = (this.string != null) && (this.iInt != -1);
    return filled;
  }

  public void setString(String string) {
    if(this.string == null){
      this.string = string;
    }else{
      throw new RuntimeException("You try to override an already setValue"); 
    }
  }

  public void setiInt(int iInt) {
    if(this.iInt == -1){
      this.iInt = iInt;
    }else{
      throw new RuntimeException("You try to override an already setValue");
    }
  }
}

चूंकि getInstance()हर बार एक ही इंस्टेंस रिटर्न देता है, मुझे लगता है कि यह काम कर सकता है। अगर यह बहुत गलत है तो मैं इसे हटा दूंगा, मुझे इस विषय में दिलचस्पी है।


-1

मुझे लगता है कि यह एक आम समस्या है। सिंगलटन के "प्राप्त" से सिंगलटन के "इनिशियलाइज़ेशन" को अलग करना काम कर सकता है (यह उदाहरण डबल चेक किए गए लॉकिंग की भिन्नता का उपयोग करता है)।

public class MySingleton {

    private static volatile MySingleton INSTANCE;

    @SuppressWarnings("UnusedAssignment")
    public static void initialize(
            final SomeDependency someDependency) {

        MySingleton result = INSTANCE;

        if (result != null) {
            throw new IllegalStateException("The singleton has already "
                    + "been initialized.");
        }

        synchronized (MySingleton.class) {
            result = INSTANCE;

            if (result == null) {
                INSTANCE = result = new MySingleton(someDependency);
            } 
        }
    }

    public static MySingleton get() {
        MySingleton  result = INSTANCE;

        if (result == null) {
            throw new IllegalStateException("The singleton has not been "
                    + "initialized. You must call initialize(...) before "
                    + "calling get()");
        }

       return result;
    }

    ...
}

हमेशा इनिशियलाइज़ विधि में "परिणाम" वापस कर सकता हूँ और साथ ही साथ मुझे लगता है।
माइकल एंड्रयूज

-2

सिंगलटन, निश्चित रूप से, एक "एंटी-पैटर्न" (परिवर्तनशील राज्य के साथ एक स्थिर की परिभाषा)।

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


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

एक सिंगलटन का सही उपयोग अक्षम कोड प्रदर्शित करना है।
टॉम हैटिन -

-6

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

एक तर्क के साथ एक सिंगलटन को कोई मतलब नहीं है - अगर आपने लिखा तो क्या होगा:

Singleton s = SingletonHolder.getInstance(1);
Singleton t = SingletonHolder.getInstance(2); //should probably throw IllegalStateException

आपका सिंगलटन भी थ्रेड-सेफ नहीं है क्योंकि कई थ्रेड्स एक साथ कॉल कर सकते हैं getInstanceजिसके परिणामस्वरूप एक से अधिक उदाहरण बनाए जा सकते हैं (संभवतः विभिन्न मूल्यों के साथ x)।


यह काफी बहस का मुद्दा है।
अल्बर्टोपीएल

1
हाँ यह बहस का मुद्दा है; इसलिए "आम तौर पर" शब्द का मेरा उपयोग। मुझे लगता है कि यह उचित है कि वे आम तौर पर एक बुरा विचार माना जाता है कहने के लिए
oxbow_lakes

यह बहस का मुद्दा है - कुछ लोग दावा करते हैं कि "एंटी-पैटर्न" कहा जाता है, पैटर्न की परिभाषा फिट होती है, यह सिर्फ इतना है कि वे खराब पैटर्न हैं।
टॉम हॉल्टिन -

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

मुझे लगता है कि आप गलत समझ सकते हैं कि "वितरित" का क्या मतलब है? आप जो चाहते हैं उसे प्राप्त करने के अन्य तरीके हैं: क्या आपने निर्भरता इंजेक्शन पर विचार किया है? या JNDI?
oxbow_lakes
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.