कदाचित तुम्ही ऐकले असेल की सिंगलटन सिंगल माल्ट स्कॉच व्हिस्की चांगली आहे? बरं, अल्कोहोल तुमच्या आरोग्यासाठी हानिकारक आहे, म्हणून आज आम्ही तुम्हाला त्याऐवजी जावामधील सिंगलटन डिझाइन पॅटर्नबद्दल सांगू.

आम्ही यापूर्वी ऑब्जेक्ट्सच्या निर्मितीचे पुनरावलोकन केले होते, म्हणून आम्हाला माहित आहे की Java मध्ये ऑब्जेक्ट तयार करण्यासाठी, आपल्याला असे काहीतरी लिहावे लागेल:


Robot robot = new Robot(); 
    

पण वर्गाचा एकच प्रसंग तयार केला जाईल याची खात्री करायची असेल तर?

नवीन Robot() स्टेटमेंट अनेक ऑब्जेक्ट्स तयार करू शकते आणि असे करण्यापासून आम्हाला काहीही अडवत नाही. येथेच सिंगलटन पॅटर्न बचावासाठी येतो.

समजा तुम्हाला एखादा अॅप्लिकेशन लिहायचा आहे जो प्रिंटरशी कनेक्ट होईल — फक्त एक प्रिंटर — आणि त्याला प्रिंट करायला सांगा:


public class Printer { 
 
	public Printer() { 
	} 
     
	public void print() { 
    	… 
	} 
}
    

हा सामान्य वर्गासारखा दिसतो... पण! एक "पण" आहे: मी माझ्या प्रिंटर ऑब्जेक्टची अनेक उदाहरणे तयार करू शकतो आणि त्यावर वेगवेगळ्या ठिकाणी कॉल पद्धती करू शकतो. हे माझ्या प्रिंटरला हानी पोहोचवू शकते किंवा खराब करू शकते. त्यामुळे आमच्या प्रिंटरचा एकच प्रसंग आहे याची आम्हाला खात्री करावी लागेल आणि तेच सिंगलटन आमच्यासाठी करेल!

सिंगलटन तयार करण्याचे मार्ग

सिंगलटन तयार करण्याचे दोन मार्ग आहेत:

  • खाजगी कन्स्ट्रक्टर वापरा;
  • एकाच प्रसंगात प्रवेश देण्यासाठी सार्वजनिक स्थिर पद्धत निर्यात करा.

प्रथम खाजगी कन्स्ट्रक्टर वापरण्याचा विचार करूया. हे करण्यासाठी, आम्हाला आमच्या वर्गात एक क्षेत्र अंतिम म्हणून घोषित करावे लागेल आणि ते सुरू करावे लागेल. आम्ही ते अंतिम म्हणून चिन्हांकित केल्यामुळे , आम्हाला माहित आहे की ते अपरिवर्तनीय असेल , म्हणजे आम्ही यापुढे ते बदलू शकत नाही.

वर्गाच्या बाहेर वस्तू तयार करणे टाळण्यासाठी तुम्हाला कन्स्ट्रक्टरला खाजगी म्हणून घोषित करणे देखील आवश्यक आहे . हे आमच्यासाठी हमी देते की प्रोग्राममध्ये आमच्या प्रिंटरची इतर कोणतीही उदाहरणे नसतील. सुरुवातीच्या वेळी कन्स्ट्रक्टरला फक्त एकदाच कॉल केला जाईल आणि आमचा प्रिंटर तयार करेल :


public class Printer { 
     
	public static final Printer PRINTER = new Printer(); 
     
	private Printer() { 
	} 
 
	public void print() { 
        // Printing... 
 
	} 
}
    

प्रिंटर सिंगलटन तयार करण्यासाठी आम्ही एका खाजगी कन्स्ट्रक्टरचा वापर केला — फक्त एकच उदाहरण असेल. दप्रिंटरव्हेरिएबलमध्ये स्टॅटिक मॉडिफायर आहे , कारण ते कोणत्याही ऑब्जेक्टचे नाही, तर प्रिंटर क्लासचे आहे.

आता आमच्या वर्गाच्या एका प्रसंगात प्रवेश देण्यासाठी स्थिर पद्धत वापरून सिंगलटन तयार करण्याचा विचार करूया (आणि लक्षात घ्या की फील्ड आता खाजगी आहे ):


public class Printer { 
 
	private static final Printer PRINTER = new Printer(); 
 
	private Printer() { 
	} 
 
	public static Printer getInstance() { 
    	return PRINTER; 
	} 
     
	public void print() { 
        // Printing... 
	} 
} 
    

येथे आपण getInstance() पद्धत कितीही वेळा कॉल केली तरी आपल्याला तीच मिळेलप्रिंटरवस्तू

खाजगी कन्स्ट्रक्टर वापरून सिंगलटन तयार करणे सोपे आणि अधिक संक्षिप्त आहे. इतकेच काय, API स्पष्ट आहे, कारण सार्वजनिक क्षेत्र अंतिम म्हणून घोषित केले आहे , जे हमी देते की त्यात नेहमी समान ऑब्जेक्टचा संदर्भ असेल.

स्टॅटिक मेथड पर्यायामुळे एपीआय न बदलता सिंगलटनला नॉन-सिंगलटन क्लासमध्ये बदलण्याची लवचिकता मिळते. getInstance () पद्धत आम्हाला आमच्या ऑब्जेक्टचे एकच उदाहरण देते, परंतु आम्ही ते बदलू शकतो जेणेकरून ते कॉल करणार्‍या प्रत्येक वापरकर्त्यासाठी स्वतंत्र उदाहरण देईल.

स्टॅटिक पर्याय आपल्याला जेनेरिक सिंगलटन फॅक्टरी देखील लिहू देतो.

स्थिर पर्यायाचा अंतिम फायदा असा आहे की आपण ते पद्धती संदर्भासह वापरू शकता.

तुम्हाला वरीलपैकी कोणत्याही फायद्यांची आवश्यकता नसल्यास, आम्ही सार्वजनिक क्षेत्राचा समावेश असलेला पर्याय वापरण्याची शिफारस करतो.

जर आम्हाला सीरियलायझेशनची आवश्यकता असेल, तर फक्त सीरियलायझ करण्यायोग्य इंटरफेस लागू करणे पुरेसे नाही . आम्हाला readResolve पद्धत देखील जोडण्याची आवश्यकता आहे , अन्यथा आम्हाला deserialization दरम्यान एक नवीन सिंगलटन उदाहरण मिळेल.

बाइट्सच्या क्रमानुसार ऑब्जेक्टची स्थिती जतन करण्यासाठी सीरियलायझेशन आवश्यक आहे आणि त्या बाइट्समधून ऑब्जेक्ट पुनर्संचयित करण्यासाठी डीसीरियलायझेशन आवश्यक आहे. आपण या लेखात अनुक्रमीकरण आणि डीसीरियलायझेशनबद्दल अधिक वाचू शकता .

आता आमचे सिंगलटन पुन्हा लिहू:


public class Printer implements Serializable { 
 
	private static final Printer PRINTER = new Printer(); 
 
	private Printer() { 
	} 
 
	public static Printer getInstance() { 
    	return PRINTER; 
	} 
} 
    

आता आम्ही ते सीरियल आणि डीसीरियल करू.

लक्षात घ्या की खाली दिलेले उदाहरण जावा मधील सीरियलायझेशन आणि डीसीरियलायझेशनसाठी मानक यंत्रणा आहे. कोडमध्ये काय चालले आहे याची संपूर्ण माहिती तुम्ही "I/O प्रवाह" (जावा सिंटॅक्स मॉड्यूलमध्ये) आणि "सिरियलायझेशन" (जावा कोअर मॉड्यूलमध्ये) अभ्यासल्यानंतर येईल.

var printer = Printer.getInstance(); 
var fileOutputStream = new FileOutputStream("printer.txt"); 
var objectOutputStream = new ObjectOutputStream(fileOutputStream); 
objectOutputStream.writeObject(printer); 
objectOutputStream.close(); 
 
var fileInputStream = new FileInputStream("printer.txt"); 
var objectInputStream = new ObjectInputStream(fileInputStream); 
var deserializedPrinter =(Printer) objectInputStream.readObject(); 
objectInputStream.close(); 
 
System.out.println("Singleton 1 is: " + printer); 
System.out.println("Singleton 2 is: " + deserializedPrinter);
    

आणि आम्हाला हा परिणाम मिळतो:

सिंगलटन 1 आहे: प्रिंटर@6be46e8f
सिंगलटन 2 आहे: प्रिंटर@3c756e4d

येथे आपण पाहतो की डीसीरियलायझेशनने आम्हाला आमच्या सिंगलटनचे वेगळे उदाहरण दिले. याचे निराकरण करण्यासाठी, आमच्या वर्गात readResolve पद्धत जोडूया :


public class Printer implements Serializable { 
 
	private static final Printer PRINTER = new Printer(); 
 
	private Printer() { 
	} 
 
	public static Printer getInstance() { 
    	return PRINTER; 
	} 
 
	public Object readResolve() { 
    	return PRINTER; 
	} 
}
    

आता आम्ही आमच्या सिंगलटनला पुन्हा सीरियल आणि डीसीरियलाइज करू:


var printer = Printer.getInstance(); 
var fileOutputStream = new FileOutputStream("printer.txt"); 
var objectOutputStream = new ObjectOutputStream(fileOutputStream); 
objectOutputStream.writeObject(printer); 
objectOutputStream.close(); 
 
var fileInputStream = new FileInputStream("printer.txt"); 
var objectInputStream = new ObjectInputStream(fileInputStream); 
var deserializedPrinter=(Printer) objectInputStream.readObject(); 
objectInputStream.close(); 
 
System.out.println("Singleton 1 is: " + printer); 
System.out.println("Singleton 2 is: " + deserializedPrinter); 
    

आणि आम्हाला मिळते:

सिंगलटन 1 आहे: com.company.Printer@6be46e8f
सिंगलटन 2 आहे: com.company.Printer@6be46e8f

readResolve () पद्धतीमुळे आम्हाला तेच ऑब्जेक्ट मिळू शकते जे आम्ही डीसीरियल केले आहे, ज्यामुळे रॉग सिंगलटन तयार होण्यास प्रतिबंध होतो.

सारांश

आज आपण सिंगलटन बद्दल शिकलो: ते कसे तयार करायचे आणि ते कधी वापरायचे, ते कशासाठी आहेत आणि ते तयार करण्यासाठी Java कोणते पर्याय ऑफर करते. दोन्ही पर्यायांची विशिष्ट वैशिष्ट्ये खाली दिली आहेत:

खाजगी बांधकाम करणारा स्थिर पद्धत
  • सोपे आणि अधिक संक्षिप्त
  • सिंगलटन फील्ड सार्वजनिक अंतिम असल्याने स्पष्ट API
  • पद्धत संदर्भासह वापरले जाऊ शकते
  • जेनेरिक सिंगलटन कारखाना लिहिण्यासाठी वापरला जाऊ शकतो
  • प्रत्येक वापरकर्त्यासाठी स्वतंत्र उदाहरण परत करण्यासाठी वापरले जाऊ शकते