Singleton (سنگلٹن) — ایک تخلیقی پیٹرن جو کلاس کی واحد مثال کو یقینی بناتا ہے اور اس تک عالمی رسائی فراہم کرتا ہے۔ Singleton موبائل ڈیویلپمنٹ میں مشترکہ وسائل (نیٹ ورک کلائنٹ، ڈیٹابیس، سیٹنگز مینیجر) کے لیے وسیع پیمانے پر استعمال ہوتا ہے۔ یہ پیٹرن GoF (1994) کی کلاسک کتاب میں بیان کیا گیا ہے اور سب سے پہچانے جانے والے پیٹرن میں سے ایک ہے۔ مزید معلومات کے لیے Refactoring Guru: Singleton ملاحظہ کریں۔
اہم نکات
Singleton — GoF (Gang of Four) کی طرف سے 1994 میں بیان کردہ ایک تخلیقی ڈیزائن پیٹرن ہے۔ یہ پیٹرن دو مسائل حل کرتا ہے: یہ کلاس کی مثال بنانے کو ایک آبجیکٹ تک محدود کرتا ہے اور اس آبجیکٹ تک عالمی رسائی فراہم کرتا ہے۔ Singleton ان وسائل کے لیے مفید ہے جو منفرد ہونے چاہئیں: سیشن فیکٹریاں، تصویری کیش، ڈیٹابیس کنکشن مینیجر، Crashlytics یا Analytics کلائنٹ۔
Singleton کا نفاذ ایک نجی کنسٹرکٹر (بیرونی تخلیق کو روکتا ہے)، واحد مثال کے ساتھ ایک جامد فیلڈ، اور ایک جامد رسائی کا طریقہ (shared، instance، getInstance) کی ضرورت ہے۔ کلائنٹ آبجیکٹ تخلیق کی فکر کیے بغیر Singleton.shared.method() کال کرتے ہیں۔ یہ پیٹرن iOS اور Android میں مقبول ہے: URLSession.shared، UserDefaults.standard، FirebaseApp.sharedInstance — یہ سب Singleton ہیں۔ تاہم، Singleton کا زیادہ استعمال Global State اینٹی پیٹرن کی طرف لے جاتا ہے۔
Singleton کے مسائل — پوشیدہ انحصاریاں (کلاسز مضمر طور پر Singleton آبجیکٹ پر منحصر ہوتی ہیں)، جانچ کی پیچیدگی (اضافی کوشش کے بغیر ٹیسٹ میں مثال کو تبدیل نہیں کیا جا سکتا)، واحد ذمہ داری کے اصول کی خلاف ورزی (Singleton اپنی مثال اور کاروباری منطق دونوں کا انتظام کرتا ہے)۔ جدید موبائل ڈیویلپمنٹ واحد مثالوں کے انتظام کے لیے DI (Dagger، Hilt، Swinject) کو ترجیح دیتی ہے — DI کنٹینر آبجیکٹ کو ایک بار بناتا ہے اور کنسٹرکٹر کے ذریعے انجیکٹ کرتا ہے۔
Swift Singleton ایک نجی ابتدائیہ کے ساتھ جامد shared خصوصیت کے ذریعے نافذ کیا جاتا ہے۔ Swift 3 کے بعد سے، جامد خصوصیات کی سست ابتداء تھریڈ محفوظ ہونے کی ضمانت ہے — مرتب کرنے والا dispatch_once کے ذریعے خود بخود ہم آہنگی شامل کرتا ہے۔ static let shared = Class() کا اعلان کرنا اور init() کو نجی بنانا کافی ہے۔ Swift کو ابتداء کے بعد سنگل تھریڈ رسائی کے لیے اضافی ہم آہنگی کی ضرورت نہیں ہے۔
final class NetworkManager {
// تھریڈ محفوظ Singleton
static let shared = NetworkManager()
private init() {
URLSessionConfiguration.default.timeoutIntervalForRequest = 30
}
private var cache = NSCache<NSString, NSData>()
func fetchData(from url: URL) async throws -> Data {
let key = url.absoluteString as NSString
if let cached = cache.object(forKey: key) {
return cached as Data
}
let (data, _) = try await URLSession.shared.data(from: url)
cache.setObject(data as NSData, forKey: key)
return data
}
}
// استعمال
let data = try await NetworkManager.shared.fetchData(from: url)
Apple Singleton — بہت سے iOS SDK آبجیکٹ Singleton استعمال کرتے ہیں: UIApplication.shared، UIScreen.main، FileManager.default، NotificationCenter.default، UserDefaults.standard۔ Apple جسمانی طور پر منفرد خدمات (ایک اسکرین، ایک ایپلیکیشن) کے لیے Singleton استعمال کرتا ہے۔ ڈیویلپر اپنی خدمات کے لیے اس پیٹرن کی نقل کرتے ہیں۔ SwiftUI میں، Singleton تک عالمی رسائی Environment اور @EnvironmentObject سے تبدیل کر دی جاتی ہے، جس سے جانچ کی صلاحیت بہتر ہوتی ہے۔
Kotlin Singleton — سب سے آسان طریقہ: object کلیدی لفظ پہلی رسائی پر سست ابتداء کے ساتھ سنگلٹن کلاس کا اعلان کرتا ہے۔ Kotlin object تھریڈ محفوظ ہے اور اضافی ہم آہنگی کی ضرورت نہیں ہے۔ اگر کنسٹرکٹر پیرامیٹرز کے ساتھ Singleton کی ضرورت ہو، تو lazy ڈیلیگیٹ کے ساتھ companion object استعمال کیا جاتا ہے۔ Android میں، Singleton اکثر Application سیاق اور Application.onCreate() کے ذریعے شروع ہونے والی خدمات کے لیے ضروری ہوتا ہے۔
// آپشن 1: object — پیرامیٹر کے بغیر سادہ Singleton
object AppPreferences {
private val prefs = Application.instance
.getSharedPreferences("app", Context.MODE_PRIVATE)
var isFirstLaunch: Boolean
get() = prefs.getBoolean("first_launch", true)
set(value) = prefs.edit { putBoolean("first_launch", value) }
}
// آپشن 2: companion object — پیرامیٹر کے ساتھ Singleton
class ApiClient private constructor(baseUrl: String) {
companion object {
@Volatile
private var instance: ApiClient? = null
fun getInstance(baseUrl: String): ApiClient {
return instance ?: this.synchronized {
instance ?: ApiClient(baseUrl).also { instance = it }
}
}
}
fun request(endpoint: String): String { /* ... */ }
}
Android SDK Singleton — بہت سے Android نظام خدمات Singleton نافذ کرتی ہیں: context.getSystemService()، Room.databaseBuilder()، Retrofit.Builder()۔ مثالوں میں SharedPreferences، MediaPlayer، AudioManager شامل ہیں۔ Android ایپلیکیشنز میں، Singleton اکثر ذخیروں، مینیجرز اور فیکٹریوں کے لیے استعمال ہوتا ہے۔ Google Singleton کو DI (Hilt، Koin) سے تبدیل کرنے کی سفارش کرتا ہے، جہاں Singleton دائرہ کار (Scope.Singleton یا @Singleton) کنٹینر کے ذریعے منظم کیا جاتا ہے جبکہ کلاس جانچ کے قابل رہتی ہے۔
Thread safety — ملٹی تھریڈ ماحول میں Singleton کے لیے ایک اہم ضرورت ہے۔ ہم آہنگی کے بغیر، دو تھریڈ ایک ساتھ instance == null چیک کر سکتے ہیں اور دو مثالیں بنا سکتے ہیں۔ حل پہلی تخلیق کے دوران لاک کرنا اور ابتداء کے بعد جاری کرنا ہے۔ Swift میں، جامد خصوصیات (static let) ڈیفالٹ طور پر تھریڈ محفوظ ہیں۔ Kotlin میں، object تھریڈ محفوظ ہے۔ Kotlin میں Java طرز کے لیے، synchronized یا @Volatile + double-check locking استعمال کیا جاتا ہے۔
| زبان | میکانزم | تھریڈ تحفظ | سست ابتداء |
|---|---|---|---|
| Swift | static let | dispatch_once (خودکار) | ہاں، پہلی رسائی پر |
| Kotlin object | Object اعلان | کلاس ابتدائیہ تھریڈ محفوظ | ہاں، پہلی رسائی پر |
| Kotlin companion | synchronized + @Volatile | Double-checked locking | ہاں، lazy یا synchronized کے ذریعے |
| Java | synchronized + volatile | Double-checked locking | ہاں، getInstance() میں |
Double-checked locking — Singleton کی سست ابتداء کے لیے ایک پیٹرن ہے۔ پہلی جانچ ہم آہنگی کے بغیر (تیز اگر مثال پہلے سے موجود ہے)، دوسری synchronized کے اندر (صرف ایک تھریڈ کے ذریعے تخلیق)۔ @Volatile تمام تھریڈز کے لیے تبدیلیوں کی مرئیت کو یقینی بناتا ہے۔ volatile کے بغیر، دوسرا تھریڈ جزوی طور پر بنایا گیا آبجیکٹ دیکھ سکتا ہے۔ Kotlin میں، LazyThreadSafetyMode.SYNCHRONIZED کے ساتھ lazy ڈیلیگیٹ خود بخود double-checked locking نافذ کرتا ہے۔
Dependency Injection — واحد مثالوں کے انتظام کے لیے Singleton کا ایک متبادل ہے۔ DI کنٹینر (Dagger، Hilt، Koin، Swinject) Singleton دائرہ کار میں آبجیکٹ کو ایک بار بناتا ہے اور کنسٹرکٹر کے ذریعے انجیکٹ کرتا ہے۔ کلاس اپنی Singleton کیفیت کے بارے میں نہیں جانتی — کنٹینر فیصلہ کرتا ہے۔ کوڈ جانچ کے قابل ہو جاتا ہے: ٹیسٹ میں DI ماڈیول کو فرضی ماڈیول سے تبدیل کر دیا جاتا ہے۔ DI فوائد: کنسٹرکٹر میں واضح انحصاریاں، اوور رائڈ کرنے کی اہلیت، متحدہ لائف سائیکل۔
Singleton کب جائز ہے — نظام سطح کے آبجیکٹ: Crashlytics، Analytics، Logging۔ یہ خدمات AppDelegate/Application میں ایک بار شروع ہوتی ہیں اور ہر جگہ استعمال ہوتی ہیں۔ ان کے لیے DI ضرورت سے زیادہ ہے۔ Singleton تصویری کیش (NSCache، Coil، Glide) کے لیے بھی آسان ہے، جہاں عالمی رسائی کارکردگی کی وجہ سے جائز ہے۔ باقی سب کے لیے، DI ترجیحی ہے: یہ انحصاریوں کو ظاہر کرتا ہے، جانچ اور ری فیکٹرنگ کو آسان بناتا ہے۔
ہائبرڈ طریقہ — ٹیسٹ کے لیے اوور رائڈ کرنے کی صلاحیت کے ساتھ Singleton۔ Swift میں، ایک پروٹوکول + جامد خصوصیت جسے ٹیسٹ تبدیل کر سکتے ہیں (مثال کے طور پر، URLSession کے لیے URLProtocol کے ذریعے)۔ Kotlin میں، انجیکٹ ایبل خصوصیت کے ساتھ ایک کھلی کلاس، جہاں ٹیسٹ ریفلیکشن یا سیٹر کے ذریعے فرضی سیٹ کرتے ہیں۔ یہ طریقہ Singleton کی سادگی کو برقرار رکھتا ہے لیکن جانچ کی صلاحیتیں فراہم کرتا ہے۔ Google Android کے لیے Hilt تجویز کرتا ہے، Apple iOS کے لیے DI مسلط نہیں کرتا — انتخاب ٹیم پر منحصر ہے۔
اکثر پوچھے گئے سوالات
نہیں، Singleton ایک GoF پیٹرن ہے، لیکن اس کا بار بار غلط استعمال اسے Global State اینٹی پیٹرن میں تبدیل کر دیتا ہے۔ Singleton جسمانی طور پر منفرد وسائل (اسکرین، پرنٹر، فائل سسٹم) کے لیے جائز ہے۔ مسائل اس وقت پیدا ہوتے ہیں جب Singleton ڈیٹا کے انتظام کے لیے استعمال کیا جائے: پوشیدہ انحصاریاں، جانچ کی پیچیدگی، واحد ذمہ داری کے اصول کی خلاف ورزی۔ جدید متبادل Singleton دائرہ کار کے ساتھ DI ہے۔
تین طریقے: (1) پروٹوکول کے ذریعے — Singleton پروٹوکول نافذ کرتا ہے، ٹیسٹ نفاذ تبدیل کرتے ہیں؛ (2) DI کے ذریعے — Singleton کنسٹرکٹر کے ذریعے انحصار کے طور پر انجیکٹ ہوتا ہے؛ (3) reset طریقہ کے ذریعے — Singleton کے پاس ٹیسٹ میں حالت دوبارہ ترتیب دینے کا طریقہ ہے (صرف ٹیسٹ بلڈ کے لیے)۔ پہلا طریقہ ترجیحی ہے، تیسرا پروڈکشن کے لیے خطرناک ہے۔ Swift ٹیسٹ میں رن ٹائم ہیرا پھیری کے ذریعے shared خصوصیت کو تبدیل کرنے کی اجازت دیتا ہے۔
Kotlin object ایک زبان کا ڈھانچہ ہے جو بائٹ کوڈ سطح پر Singleton بناتا ہے۔ نجی کنسٹرکٹر اور getInstance() کے ساتھ Java نفاذ کے برعکس، object تھریڈ تحفظ، سست ابتداء کو یقینی بناتا ہے اور وراثت کو منع کرتا ہے۔ Java Singleton کو ملٹی تھریڈ ماحول میں درست کام کے لیے دستی ہم آہنگی (synchronized) اور volatile کی ضرورت ہے۔ Kotlin object Android میں سب سے محفوظ اور مختصر طریقہ ہے۔
Singleton کو وراثت میں لینا پیٹرن توڑتا ہے: اگر Singleton کلاس وراثت میں مل سکتی ہے، تو ایک ذیلی کلاس دوسری مثال بنا سکتی ہے، جو انفرادیت کی خلاف ورزی کرتی ہے۔ Swift میں، final class وراثت کو منع کرتا ہے۔ Kotlin object وراثت میں نہیں مل سکتا (object sealed ہے)۔ اگر تغیر پذیری کے ساتھ Singleton کی ضرورت ہو، تو Singleton دائرہ کار کے ساتھ DI کنٹینر استعمال کریں: یہ واحد مثال کو یقینی بناتا ہے اور انٹرفیس کے ذریعے وراثت کی حمایت کرتا ہے۔
پیرامیٹر init(context: Application) یا getInstance(param) کے ذریعے دیے جاتے ہیں۔ Kotlin object پیرامیٹر قبول نہیں کرتا — فیکٹری طریقہ getInstance(param) کے ساتھ companion object استعمال کریں۔ Hilt مسئلہ حل کرتا ہے: @Singleton + @Inject constructor(context: Application) — DI کنٹینر خود بخود Application سیاق انجیکٹ کرتا ہے۔ Retrofit کلائنٹ کے لیے، پیرامیٹر (baseUrl, interceptors) DI ماڈیول میں builder کے ذریعے دیے جاتے ہیں۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں