Creational — Oluşturucu Desenler
Singleton
Tek Örnek Deseni
Amaç: Bir sınıftan uygulama boyunca yalnızca bir tane nesne oluşturulmasını garanti etmek ve bu nesneye her yerden erişilebilen tek bir giriş noktası sağlamak.
Basit Anlatım
Teknik terim yok — günlük hayattan bir benzetme
Bir ülkeyi düşünün. O ülkenin aynı anda yalnızca bir tane cumhurbaşkanı olur. Vatandaşlar, bakanlar, gazeteciler… herkes "cumhurbaşkanı" dediğinde aynı kişiden bahseder. Kimse kalkıp kendine ikinci bir cumhurbaşkanı seçemez.
Ya da bir apartmanı düşünün: binanın tek bir kapıcısı var. Hangi daireden seslenirseniz seslenin, aynı kapıcı gelir. Her dairenin kendi kapıcısını tutması hem gereksiz masraf olurdu hem de kargaşa yaratırdı: "Çöpü kim aldı? Paketi kime bıraktılar?"
Neden önemli?
Bazı şeylerin birden fazla olması sorun çıkarır. Bir ofiste tek bir ortak takvim varsa herkes toplantıları aynı yerden görür. Herkes kendi takvimini tutarsa iki toplantı aynı odaya aynı saatte konur.
Teknik Anlamı
Bir yazılımcının bakış açısıyla
Singleton, Creational (oluşturucu) kategorisinde bir desendir. Bir sınıfın tek bir örneğe (instance) sahip olmasını sınıfın kendisine garanti ettirir.
Nasıl sağlanır?
- Constructor
privateyapılır; dışarıdannewile nesne oluşturulamaz. - Sınıf, kendi tek örneğini
staticbir alanda tutar. - Bu örneğe
staticbir property (genellikleInstance) üzerinden erişilir. - Çok iş parçacıklı (multi-thread) ortamda iki thread'in aynı anda iki nesne üretmemesi için thread-safe başlatma gerekir. .NET'te bunun en temiz yolu
Lazy<T>kullanmaktır.
Ne zaman kullanılır?
- Paylaşılan tek bir kaynak varsa: konfigürasyon, loglama, önbellek (cache), bağlantı havuzu.
- Nesnenin oluşturulması pahalıysa ve tekrar tekrar oluşturmak anlamsızsa.
Avantajlar
- Tek örnek garantisi ve kontrollü erişim.
- Lazy (tembel) başlatma ile ihtiyaç duyulana kadar oluşturulmaz.
Dezavantajlar ve uyarılar
- Aslında bir global state'tir; gizli bağımlılıklar oluşturur.
- Birim testlerde taklit (mock) etmek zordur.
- Single Responsibility'yi zorlar: sınıf hem işini yapar hem kendi yaşam döngüsünü yönetir.
services.AddSingleton<IFoo, Foo>() ile kayıt yapılır. Böylece tek örnek garantisi korunur ama test edilebilirlik kaybolmaz.C# ile Uygulama
Adım adım, çalışan kod örneği
Senaryo: Uygulamanın her yerinden kullanılan bir AppSettings (ayarlar) sınıfı. Ayarlar dosyadan bir kez okunmalı ve herkes aynı nesneyi kullanmalı.
Adım 1 Thread-safe Singleton sınıfı
Lazy<T> sayesinde nesne ilk erişimde ve yalnızca bir kez oluşturulur; thread güvenliğini .NET üstlenir.
public sealed class AppSettings
{
// Lazy<T>: ilk erişimde oluşturur, varsayılan olarak thread-safe'tir.
private static readonly Lazy<AppSettings> _instance =
new(() => new AppSettings());
public static AppSettings Instance => _instance.Value;
public string ConnectionString { get; private set; }
public int MaxUsers { get; set; }
// private constructor: dışarıdan "new AppSettings()" yazılamaz.
private AppSettings()
{
Console.WriteLine(">> AppSettings oluşturuldu (dosyadan okunuyor...)");
ConnectionString = "Server=localhost;Database=Shop";
MaxUsers = 100;
}
}Adım 2 Singleton'ı kullanan iki farklı servis
İki ayrı sınıf, birbirinden habersiz şekilde aynı ayarlar nesnesine erişir.
public class OrderService
{
public void PrintConfig() =>
Console.WriteLine($"OrderService -> {AppSettings.Instance.ConnectionString}");
}
public class UserService
{
public void IncreaseLimit() => AppSettings.Instance.MaxUsers += 50;
}Adım 3 Kullanım
Tüm parçaları bir araya getiren istemci (client) kodu:
Console.WriteLine("Program başladı.");
var orders = new OrderService();
var users = new UserService();
orders.PrintConfig(); // AppSettings burada ilk kez oluşturulur
users.IncreaseLimit(); // aynı nesne üzerinde değişiklik
var a = AppSettings.Instance;
var b = AppSettings.Instance;
Console.WriteLine($"MaxUsers: {a.MaxUsers}");
Console.WriteLine($"a ve b aynı nesne mi? {ReferenceEquals(a, b)}");
// var c = new AppSettings(); // DERLEME HATASI: constructor privateKonsol çıktısı
Program başladı. >> AppSettings oluşturuldu (dosyadan okunuyor...) OrderService -> Server=localhost;Database=Shop MaxUsers: 150 a ve b aynı nesne mi? True
Kodda dikkat edilmesi gerekenler
- "AppSettings oluşturuldu" mesajı yalnızca bir kez yazıldı;
Instance'a kaç kez erişilirse erişilsin yeni nesne üretilmedi. UserService'in yaptığı değişiklik (MaxUsers += 50) diğer herkes tarafından görüldü, çünkü herkes aynı nesneyi paylaşıyor.sealedanahtar kelimesi, kalıtım yoluyla ikinci bir örnek oluşturulmasını engeller.