Bir sınıfın sadece bir nesne yaratmasını ve sürekli olarak aynı nesnenin kullanılmasını istediğimiz durumlarda tercih ederiz.
Bir sınıftan bir tane nesne olmasından kasıt ise, herkesin istediği zaman bu sınıfın bir nesnesini oluşturmaya çalışamaması ve oluşturamaması, var olan tek nesneyi kullanmasıdır.
UML Class Diyagramı
Kullanım Sıklığı: orta-yüksek
Singleton Prensipleri
- Singleton, bir sınıfın örneklenmesini kısıtlar ve sınıfın yalnızca bir örneğinin bulunmasını sağlar.
- Singleton sınıfı, sınıfın örneğini almak için genel bir erişim noktası sağlamalıdır.
- Singleton genellikle logging, caching ve thread pool için kullanılır.
- Singleton desing pattern ayrıca Abstract Factory, Builder, Prototype, Facede gibi diğer tasarım modellerinde de kullanılılır.
C# Singleton Design Pattern Uygulama
Sınıfın diğer sınıflardan örneklenmesini kısıtlamak için constructor private yapılır. Böylece sınıfa direkt erişimi kapatmış oluruz.
Sınıfın tek örneği (instance) aynı class içinde private static değişken olarak tanımlanır.
Sınıfın örneğini (instance) döndüren yani constructor’ın yerini alacak public static bir metot tanımlanır. Bu metot sınıfın örneğini kontrolü bir şekilde dış dünyaya açmak için kullanılır.
Eager Initialization
Eager Initialization diye adlandırılan bu yapıda sınıfın örneği (instance) sınıf yüklemesi (class loading) sırasında oluşur. Bu yöntemin dezavantajı istemci (client) uygulaması onu kullanmıyor olsa bile oluşturulmuş olmasıdır.
Singleton sınıfınız çok fazla kaynak kullanmıyorsa, kullanılacak yaklaşım bu olmalıdır. Çoğunlukla, Dosya Sistemi (File System), Veritabanı bağlantıları (Database Connection) vb. senaryolarda singleton sınıflar oluşturulur.
public class EagerSingleton
{
public static BasicSingleton instance;
private BasicSingleton()
{
}
public static BasicSingleton GetInstance()
{
return instance;
}
}
Lazy Initialization
Lazy Loading (Geç Yüklemeli), İlk senaryoda singleton olan nesnenin sınıf yüklenirken direk oluşturuluyordu. Ancak herzaman bunu istemeyiz özellikle bu pahalı bir nesne ise biz bunu kullanma zamanına kadar oluşturmak istemeyiz. Böyle bir durumda Lazy Loading ile yaratılmasına ihtiyaç olana kadar geciktirebiliriz.
public class LazySingleton
{
private static LazySingleton instance;
private LazySingleton()
{
}
/*
Singleton modelini uygulamak için Lazy Initialization örneği global erişim metodunda oluşturlur.
*/
public static LazySingleton GetInstance()
{
if (instance == null)
{
instance= new LazySingleton();
}
return instance;
}
}
Thread Safe Singleton
İş parçacığı açısından güvenli bir tekil sınıf oluşturmanın basit bir yolu, küresel erişim yöntemini eşitleyerek, bu yöntemi aynı anda yalnızca bir iş parçacığının yürütebilmesini sağlamaktır.
public class MultiThreadSafeSingleton
{
private static MultiThreadSafeSingleton instance;
private MultiThreadSafeSingleton()
{
}
private static readonly object lock_obj = new object();
/*
Çift kontrollü kilitleme prensibi. Bu yaklaşımda, bir singleton sınıfının yalnızca bir örneğinin oluşturulmasını sağlamak için ek bir denetimle if koşulunun içinde senkronize edilmiş blok kullanılır.
*/
public static MultiThreadSafeSingleton GetInstance()
{
{
lock (lock_obj)
{
if (instance == null)
{
instance = new MultiThreadSafeSingleton();
}
}
}
return instance;
}
}
C# Singleton Design Pattern Örnek Uygulama
Örnek uygulamamıza Singleton design pattern’ın gereksinimlerini uyguluyoruz artı olarak bir data adında değişken tanımı yapıyoruz. Program.cs tarafında ürettiğimiz ilk nesnede data ya değer ataması yapıp sonradan üreteceğimiz tüm nesnelerin üzerindende data’yı okumaya çalışacağız. Böylece tek bir nesne üzerinden devam edildiğini hep birlikte görebiliriz.
public class SampleSingleton
{
private static SampleSingleton sampleSingleton;
private string data;
public string Data
{
get { return data; }
set { data = value; }
}
//protected erişim beliryicisi tanımlanarak da Yapıcı metot üzerinde kısıtlama uygulayabiliriz.
protected SampleSingleton()
{
}
public static SampleSingleton CreateSampleSingleton()
{
if (sampleSingleton == null)
{
sampleSingleton= new SampleSingleton();
}
return sampleSingleton;
}
}
Program.cs – Main Method
//Kontrollü bir şekilde nesne oluşturup içerisine data ataması gerçekleştiriyoruz.
SampleSingleton sample1 = SampleSingleton.CreateSampleSingleton();
sample1.Data = "First Instance";
//Nesne üretmeye devam ediyoruz.
SampleSingleton sample2 = SampleSingleton.CreateSampleSingleton();
SampleSingleton sample3 = SampleSingleton.CreateSampleSingleton();
//Ürettiğimiz nesnelerden data değişkenimizi çağırdığımız zaman hep aynı değerin geri döndüğünü fark edeceksiniz. Bu bize aynı nesne üzerinde olduğumuzu gösterir.
Console.WriteLine("Object-sample1: " + sample1.Data);
Console.WriteLine("Object-sample2: " + sample2.Data);
Console.WriteLine("Object-sample3: " + sample3.Data);
Console.WriteLine("-------------------------------");
//Bir kontrol'de if ile yapalım.
if (sample1 == sample2 && sample1 == sample2 && sample2==sample3)
{
Console.WriteLine("Objects are the same instance");
}
Sonuç
Object-sample1: First Instance
Object-sample2: First Instance
Object-sample3: First Instance
-------------------------------
Objects are the same instance