Singleton (tekil) — bir sınıfın tek örneğini garanti eden ve ona genel erişim noktası sağlayan oluşturucu kalıptır. Singleton mobil geliştirmede paylaşılan kaynaklar (ağ istemcileri, veritabanları, ayar yöneticileri) için yaygın olarak kullanılır. Kalıp, klasik GoF kitabında (1994) tanımlanmıştır ve en tanınabilir kalıplardan biri olmaya devam etmektedir. Daha fazla bilgi için Refactoring Guru: Singleton adresini ziyaret edin.
Önemli Noktalar
Singleton — GoF (Gang of Four) tarafından 1994'te tanımlanan bir oluşturucu tasarım kalıbıdır. Kalıp iki sorunu çözer: bir sınıfın örneklenmesini tek bir nesneyle sınırlar ve bu nesneye genel erişim sağlar. Singleton, benzersiz olması gereken kaynaklar (oturum fabrikaları, görüntü önbellekleri, veritabanı bağlantı yöneticileri, Crashlytics veya Analytics istemcileri) için kullanışlıdır.
Singleton uygulaması özel bir yapıcı (dış oluşturmayı engeller), tek örnekle statik bir alan ve statik bir erişim yöntemi (shared, instance, getInstance) gerektirir. İstemciler, nesne oluşturmayı düşünmeden Singleton.shared.method() çağrısı yapar. Kalıp iOS ve Android'de popülerdir: URLSession.shared, UserDefaults.standard, FirebaseApp.sharedInstance — hepsi Singleton'dır. Ancak Singleton'ın aşırı kullanımı Global State anti-kalıbına yol açar.
Singleton sorunları — gizli bağımlılıklar (sınıflar örtük olarak Singleton nesnesine bağımlıdır), test karmaşıklığı (ek çaba olmadan testlerde örneğin değiştirilememesi), Tek Sorumluluk İlkesi'nin ihlali (Singleton hem kendi örneğini hem de iş mantığını yönetir). Modern mobil geliştirme, tek örnekleri yönetmek için DI'yi (Dagger, Hilt, Swinject) tercih eder — DI kapsayıcısı nesneyi bir kez oluşturur ve yapıcı aracılığıyla enjekte eder.
Swift Singleton, özel bir başlatıcıya sahip statik bir shared özelliği aracılığıyla uygulanır. Swift 3'ten bu yana, statik özelliklerin geç başlatılmasının iş parçacığı güvenli olduğu garanti edilir — derleyici dispatch_once aracılığıyla otomatik olarak senkronizasyon ekler. static let shared = Class() bildirmek ve init()'i özel yapmak yeterlidir. Swift, başlatmadan sonra tek iş parçacıklı erişim için ek senkronizasyon gerektirmez.
final class NetworkManager {
// İş parçacığı güvenli 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
}
}
// Kullanım
let data = try await NetworkManager.shared.fetchData(from: url)
Apple Singleton — birçok iOS SDK nesnesi Singleton kullanır: UIApplication.shared, UIScreen.main, FileManager.default, NotificationCenter.default, UserDefaults.standard. Apple, fiziksel olarak benzersiz hizmetler (bir ekran, bir uygulama) için Singleton kullanır. Geliştiriciler bu kalıbı kendi hizmetleri için kopyalar. SwiftUI'de, Singleton'a genel erişim Environment ve @EnvironmentObject ile değiştirilir ve test edilebilirlik iyileştirilir.
Kotlin Singleton — en basit yol: object anahtar sözcüğü, ilk erişimde geç başlatma ile bir tekil sınıf bildirir. Kotlin object iş parçacığı güvenlidir ve ek senkronizasyon gerektirmez. Yapıcı parametreleri olan bir Singleton gerekiyorsa, bir lazy temsilcisi ile companion object kullanılır. Android'de Singleton, Application bağlamı ve Application.onCreate() aracılığıyla başlatılan hizmetler için genellikle gereklidir.
// Seçenek 1: object — parametresiz basit 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) }
}
// Seçenek 2: companion object — parametreli 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 — birçok Android sistem hizmeti Singleton uygular: context.getSystemService(), Room.databaseBuilder(), Retrofit.Builder(). Örnekler arasında SharedPreferences, MediaPlayer, AudioManager bulunur. Android uygulamalarında Singleton, depolar, yöneticiler ve fabrikalar için sıklıkla kullanılır. Google, Singleton'ı DI (Hilt, Koin) ile değiştirmeyi önerir; burada Singleton kapsamı (Scope.Singleton veya @Singleton) kapsayıcı tarafından yönetilirken sınıf test edilebilir kalır.
Thread safety — çoklu iş parçacığı ortamlarında Singleton için kritik bir gereksinimdir. Senkronizasyon olmadan, iki iş parçacığı aynı anda instance == null kontrolü yapabilir ve iki örnek oluşturabilir. Çözüm, ilk oluşturma sırasında kilitlemek ve başlatmadan sonra serbest bırakmaktır. Swift'te statik özellikler (static let) varsayılan olarak iş parçacığı güvenlidir. Kotlin'de object iş parçacığı güvenlidir. Kotlin'de Java stili için synchronized veya @Volatile + double-check locking kullanılır.
| Dil | Mekanizma | İş parçacığı güvenliği | Geç başlatma |
|---|---|---|---|
| Swift | static let | dispatch_once (otomatik) | Evet, ilk erişimde |
| Kotlin object | Object bildirimi | Sınıf başlatıcı iş parçacığı güvenli | Evet, ilk erişimde |
| Kotlin companion | synchronized + @Volatile | Double-checked locking | Evet, lazy veya synchronized ile |
| Java | synchronized + volatile | Double-checked locking | Evet, getInstance() içinde |
Double-checked locking — Singleton'ın geç başlatılması için bir kalıptır. İlk kontrol senkronizasyon olmadan (örnek zaten varsa hızlı), ikincisi synchronized içinde (yalnızca bir iş parçacığı tarafından oluşturma). @Volatile, tüm iş parçacıkları için değişikliklerin görünürlüğünü garanti eder. Volatile olmadan, başka bir iş parçacığı kısmen oluşturulmuş bir nesne görebilir. Kotlin'de, LazyThreadSafetyMode.SYNCHRONIZED ile lazy temsilcisi otomatik olarak double-checked locking uygular.
Dependency Injection — tek örnekleri yönetmek için Singleton'a bir alternatiftir. Bir DI kapsayıcısı (Dagger, Hilt, Koin, Swinject) nesneyi Singleton kapsamında bir kez oluşturur ve yapıcı aracılığıyla enjekte eder. Sınıf, Singleton durumunu bilmez — kapsayıcı karar verir. Kod test edilebilir hale gelir: testlerde DI modülü bir mock modülü ile değiştirilir. DI avantajları: yapıcıda açık bağımlılıklar, geçersiz kılma yeteneği, birleşik yaşam döngüsü.
Singleton ne zaman haklıdır — sistem düzeyindeki nesneler: Crashlytics, Analytics, Logging. Bu hizmetler AppDelegate/Application'da bir kez başlatılır ve her yerde kullanılır. DI onlar için aşırıdır. Singleton ayrıca görüntü önbellekleri (NSCache, Coil, Glide) için de kullanışlıdır; burada genel erişim performansla haklı çıkarılır. Geri kalan her şey için DI tercih edilir: bağımlılıkları görünür kılar, test etmeyi ve yeniden düzenlemeyi basitleştirir.
Karma yaklaşım — testler için geçersiz kılınabilir Singleton. Swift'te, testlerin değiştirebileceği bir protokol + statik özellik (örneğin, URLSession için URLProtocol aracılığıyla). Kotlin'de, testlerin yansıma veya ayarlayıcı aracılığıyla bir mock ayarladığı enjekte edilebilir bir özelliğe sahip açık bir sınıf. Bu yaklaşım Singleton'ın basitliğini korur ancak test yetenekleri sağlar. Google Android için Hilt'i önerir, Apple iOS için DI'yi dayatmaz — seçim ekibe bağlıdır.
Sıkça Sorulan Sorular
Hayır, Singleton bir GoF kalıbıdır, ancak sık yanlış kullanımı onu Global State anti-kalıbına dönüştürür. Singleton, fiziksel olarak benzersiz kaynaklar (ekran, yazıcı, dosya sistemi) için haklıdır. Singleton veri yönetimi için kullanıldığında sorunlar ortaya çıkar: gizli bağımlılıklar, test karmaşıklığı, Tek Sorumluluk İlkesi'nin ihlali. Modern alternatif, Singleton kapsamlı DI'dir.
Üç yaklaşım: (1) protokol aracılığıyla — Singleton bir protokol uygular, testler uygulamayı değiştirir; (2) DI aracılığıyla — Singleton yapıcı aracılığıyla bir bağımlılık olarak enjekte edilir; (3) reset yöntemi aracılığıyla — Singleton'ın testlerde durumu sıfırlamak için bir yöntemi vardır (yalnızca test yapıları için). İlk yaklaşım tercih edilir, üçüncüsü üretim için tehlikelidir. Swift, testlerde çalışma zamanı manipülasyonu yoluyla shared özelliğinin değiştirilmesine izin verir.
Kotlin object, bayt kod düzeyinde Singleton oluşturan bir dil yapısıdır. Özel yapıcı ve getInstance() ile Java uygulamasının aksine, object iş parçacığı güvenliğini, geç başlatmayı garanti eder ve kalıtımı yasaklar. Java Singleton, çoklu iş parçacığı ortamlarında doğru çalışma için manuel senkronizasyon (synchronized) ve volatile gerektirir. Kotlin object, Android'de en güvenli ve özlü yoldur.
Singleton'ı kalıtmak kalıbı bozar: Bir Singleton sınıfı kalıtılabilirse, bir alt sınıf ikinci bir örnek oluşturarak benzersizliği ihlal edebilir. Swift'te, final class kalıtımı yasaklar. Kotlin object kalıtılamaz (object sealed'dır). Değişkenliğe sahip bir Singleton gerekiyorsa, Singleton kapsamlı bir DI kapsayıcısı kullanın: tek bir örneği garanti eder ve arayüzler aracılığıyla kalıtımı destekler.
Parametreler init(context: Application) veya getInstance(param) aracılığıyla iletilir. Kotlin object parametre kabul etmez — bir fabrika yöntemi getInstance(param) ile companion object kullanın. Hilt sorunu çözer: @Singleton + @Inject constructor(context: Application) — DI kapsayıcısı Application bağlamını otomatik olarak enjekte eder. Bir Retrofit istemcisi için parametreler (baseUrl, interceptors) DI modülündeki bir builder aracılığıyla iletilir.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun