Java Language
एकमात्र
खोज…
परिचय
एक सिंगलटन एक ऐसा वर्ग है जिसका केवल एक ही उदाहरण है। सिंगलटन डिज़ाइन पैटर्न के बारे में अधिक जानकारी के लिए, कृपया डिज़ाइन पैटर्न टैग में सिंगलटन विषय देखें।
एनम सिंगलटन
public enum Singleton {
INSTANCE;
public void execute (String arg) {
// Perform operation here
}
}
Enums में निजी कंस्ट्रक्टर हैं, अंतिम हैं और उचित क्रमांकन मशीनरी प्रदान करते हैं। वे बहुत ही संक्षिप्त और आलसी रूप से एक धागे में सुरक्षित तरीके से आरम्भिक हैं।
जेवीएम एक गारंटी प्रदान करता है कि एनम मूल्यों को एक से अधिक बार त्वरित नहीं किया जाएगा, जो प्रतिबिंब हमलों के खिलाफ एनम सिंगलटन पैटर्न को बहुत मजबूत रक्षा प्रदान करता है।
एनम पैटर्न के विरुद्ध सुरक्षा नहीं करने वाले अन्य डेवलपर्स भौतिक रूप से स्रोत कोड में अधिक तत्व जोड़ते हैं। नतीजतन, यदि आप अपने एकल के लिए इस कार्यान्वयन शैली का चयन करते हैं तो यह जरूरी है कि आप बहुत स्पष्ट रूप से यह दस्तावेज़ दें कि उन बातों के लिए कोई नया मूल्य नहीं जोड़ा जाना चाहिए।
यह सिंगलटन पैटर्न को लागू करने का अनुशंसित तरीका है, जैसा कि प्रभावी जावा में जोशुआ बलोच द्वारा समझाया गया है।
थ्रेड सेफ सिंगलटन डबल चेकिंग लॉकिंग के साथ
इस प्रकार का सिंगलटन थ्रेड सेफ है, और सिंग्लटन इंस्टेंस बनने के बाद अनावश्यक लॉकिंग को रोकता है।
public class MySingleton {
// instance of class
private static volatile MySingleton instance = null;
// Private constructor
private MySingleton() {
// Some code for constructing object
}
public static MySingleton getInstance() {
MySingleton result = instance;
//If the instance already exists, no locking is necessary
if(result == null) {
//The singleton instance doesn't exist, lock and check again
synchronized(MySingleton.class) {
result = instance;
if(result == null) {
instance = result = new MySingleton();
}
}
}
return result;
}
}
इस पर जोर दिया जाना चाहिए - जावा एसई 5 से पहले के संस्करणों में, ऊपर दिया गया कार्यान्वयन गलत है और इसे टाला जाना चाहिए। जावा 5 से पहले जावा में डबल-चेक लॉकिंग को सही तरीके से लागू करना संभव नहीं है।
Enum के उपयोग के बिना सिंगलटन (उत्सुक आरंभीकरण)
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return INSTANCE;
}
}
यह तर्क दिया जा सकता है कि यह उदाहरण प्रभावी रूप से आलसी आरंभीकरण है। जावा भाषा विनिर्देश की धारा 12.4.1 :
निम्नलिखित में से किसी एक की पहली घटना से तुरंत पहले एक वर्ग या इंटरफ़ेस प्रकार टी को आरंभ किया जाएगा:
- T एक वर्ग है और T का एक उदाहरण बनाया गया है
- T एक वर्ग है और T द्वारा घोषित एक स्थिर विधि है
- टी द्वारा घोषित एक स्थिर क्षेत्र सौंपा गया है
- T द्वारा घोषित एक स्थिर फ़ील्ड का उपयोग किया जाता है और फ़ील्ड स्थिर चर नहीं है
- टी एक शीर्ष स्तर की कक्षा है, और टी के भीतर निहित एक मुखर कथन को निष्पादित किया जाता है।
इसलिए, जब तक कक्षा में कोई अन्य स्थिर फ़ील्ड या स्थिर विधियाँ नहीं हैं, तब तक Singleton
इंस्टेंस को प्रारंभ नहीं किया जाएगा जब तक कि विधि getInstance()
पहली बार लागू न हो जाए।
धारक वर्ग का उपयोग कर थ्रेड-सुरक्षित आलसी आरंभीकरण | बिल पुघ सिंगलटन कार्यान्वयन
public class Singleton {
private static class InstanceHolder {
static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return InstanceHolder.INSTANCE;
}
private Singleton() {}
}
यह पहली कॉल पर INSTANCE
वैरिएबल को Singleton.getInstance()
लिए आरंभ करता है, अतिरिक्त सिंक्रनाइज़ेशन की आवश्यकता के बिना स्थैतिक आरंभ के लिए भाषा की थ्रेड सुरक्षा गारंटी का लाभ उठाता है।
इस कार्यान्वयन को बिल पुघ सिंगलटन पैटर्न के रूप में भी जाना जाता है। [विकी]
एकल गायन (सिंगलटन इनहेरिटेंस)
इस उदाहरण में, बेस क्लास Singleton
getMessage()
विधि प्रदान करता है जो "Hello world!"
संदेश।
यह उपवर्गों है UppercaseSingleton
और LowercaseSingleton
ओवरराइड getMessage () संदेश के उचित प्रतिनिधित्व प्रदान करने के लिए विधि।
//Yeah, we'll need reflection to pull this off.
import java.lang.reflect.*;
/*
Enumeration that represents possible classes of singleton instance.
If unknown, we'll go with base class - Singleton.
*/
enum SingletonKind {
UNKNOWN,
LOWERCASE,
UPPERCASE
}
//Base class
class Singleton{
/*
Extended classes has to be private inner classes, to prevent extending them in
uncontrolled manner.
*/
private class UppercaseSingleton extends Singleton {
private UppercaseSingleton(){
super();
}
@Override
public String getMessage() {
return super.getMessage().toUpperCase();
}
}
//Another extended class.
private class LowercaseSingleton extends Singleton
{
private LowercaseSingleton(){
super();
}
@Override
public String getMessage() {
return super.getMessage().toLowerCase();
}
}
//Applying Singleton pattern
private static SingletonKind kind = SingletonKind.UNKNOWN;
private static Singleton instance;
/*
By using this method prior to getInstance() method, you effectively change the
type of singleton instance to be created.
*/
public static void setKind(SingletonKind kind) {
Singleton.kind = kind;
}
/*
If needed, getInstance() creates instance appropriate class, based on value of
singletonKind field.
*/
public static Singleton getInstance()
throws NoSuchMethodException,
IllegalAccessException,
InvocationTargetException,
InstantiationException {
if(instance==null){
synchronized (Singleton.class){
if(instance==null){
Singleton singleton = new Singleton();
switch (kind){
case UNKNOWN:
instance = singleton;
break;
case LOWERCASE:
/*
I can't use simple
instance = new LowercaseSingleton();
because java compiler won't allow me to use
constructor of inner class in static context,
so I use reflection API instead.
To be able to access inner class by reflection API,
I have to create instance of outer class first.
Therefore, in this implementation, Singleton cannot be
abstract class.
*/
//Get the constructor of inner class.
Constructor<LowercaseSingleton> lcConstructor =
LowercaseSingleton.class.getDeclaredConstructor(Singleton.class);
//The constructor is private, so I have to make it accessible.
lcConstructor.setAccessible(true);
// Use the constructor to create instance.
instance = lcConstructor.newInstance(singleton);
break;
case UPPERCASE:
//Same goes here, just with different type
Constructor<UppercaseSingleton> ucConstructor =
UppercaseSingleton.class.getDeclaredConstructor(Singleton.class);
ucConstructor.setAccessible(true);
instance = ucConstructor.newInstance(singleton);
}
}
}
}
return instance;
}
//Singletons state that is to be used by subclasses
protected String message;
//Private constructor prevents external instantiation.
private Singleton()
{
message = "Hello world!";
}
//Singleton's API. Implementation can be overwritten by subclasses.
public String getMessage() {
return message;
}
}
//Just a small test program
public class ExtendingSingletonExample {
public static void main(String args[]){
//just uncomment one of following lines to change singleton class
//Singleton.setKind(SingletonKind.UPPERCASE);
//Singleton.setKind(SingletonKind.LOWERCASE);
Singleton singleton = null;
try {
singleton = Singleton.getInstance();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
System.out.println(singleton.getMessage());
}
}