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.

1

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.

Singleton şunu der: "Bu şeyden yalnızca bir tane olacak. İsteyen herkes o tek olana ulaşacak, kimse yenisini yapamayacak."
2

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?

Ne zaman kullanılır?

Avantajlar

Dezavantajlar ve uyarılar

Modern .NET uygulamalarında (ASP.NET Core) genellikle elle Singleton yazmak yerine Dependency Injection container'ına services.AddSingleton<IFoo, Foo>() ile kayıt yapılır. Böylece tek örnek garantisi korunur ama test edilebilirlik kaybolmaz.
3

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 private

Konsol çı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

Özetle: Singleton, "bundan bir tane olsun ve herkes onu kullansın" der. Kullanışlıdır ama global durum yarattığı için ölçülü kullanılmalı; mümkünse DI container'ın singleton yaşam süresi tercih edilmelidir.
← Ana sayfaya dön