সম্ভবত আপনি শুনেছেন যে সিঙ্গেলটন একক মল্ট স্কচ হুইস্কি ভাল? ঠিক আছে, অ্যালকোহল আপনার স্বাস্থ্যের জন্য খারাপ, তাই আজ আমরা আপনাকে জাভাতে সিঙ্গেলটন ডিজাইন প্যাটার্ন সম্পর্কে বলব।

আমরা আগে অবজেক্ট তৈরির পর্যালোচনা করেছি, তাই আমরা জানি যে জাভাতে একটি অবজেক্ট তৈরি করতে, আপনাকে কিছু লিখতে হবে:


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 পদ্ধতিটিও যোগ করতে হবে , অন্যথায় আমরা ডিসিরিয়ালাইজেশনের সময় একটি নতুন সিঙ্গলটন উদাহরণ পাব।

বাইটের ক্রম হিসাবে একটি বস্তুর অবস্থা সংরক্ষণ করার জন্য সিরিয়ালাইজেশন প্রয়োজন এবং সেই বাইটগুলি থেকে বস্তুটিকে পুনরুদ্ধার করার জন্য ডিসিরিয়ালাইজেশন প্রয়োজন। আপনি এই নিবন্ধে সিরিয়ালাইজেশন এবং ডিসিরিয়ালাইজেশন সম্পর্কে আরও পড়তে পারেন ।

এখন আমাদের সিঙ্গেলটন আবার লিখি:


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);
    

এবং আমরা এই ফলাফল পাই:

Singleton 1 হল: Printer@6be46e8f
Singleton 2 হল: Printer@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 () পদ্ধতিটি আমাদেরকে একই অবজেক্ট পেতে দেয় যা আমরা ডিসিরিয়ালাইজ করেছি, যার ফলে দুর্বৃত্ত সিঙ্গেলটন তৈরি করা রোধ করা যায়।

সারসংক্ষেপ

আজ আমরা সিঙ্গেলটন সম্পর্কে শিখেছি: কীভাবে সেগুলি তৈরি করতে হয় এবং কখন সেগুলি ব্যবহার করতে হয়, সেগুলি কীসের জন্য এবং সেগুলি তৈরি করার জন্য জাভা কী বিকল্পগুলি অফার করে৷ উভয় বিকল্পের নির্দিষ্ট বৈশিষ্ট্য নীচে দেওয়া হল:

ব্যক্তিগত নির্মাণকারী স্ট্যাটিক পদ্ধতি
  • সহজ এবং আরো সংক্ষিপ্ত
  • সুস্পষ্ট API যেহেতু সিঙ্গলটন ক্ষেত্রটি সর্বজনীন চূড়ান্ত
  • একটি পদ্ধতি রেফারেন্স সঙ্গে ব্যবহার করা যেতে পারে
  • একটি জেনেরিক সিঙ্গলটন কারখানা লিখতে ব্যবহার করা যেতে পারে
  • প্রতিটি ব্যবহারকারীর জন্য একটি পৃথক উদাহরণ ফেরত দিতে ব্যবহার করা যেতে পারে