Singleton Design Pattern| Lazy Initialization ve Thread Safe Kullanımı

Özge Odabaş
3 min readSep 25, 2023

Bu yazıda yazılım geliştirme sürecinde karşılaşılan problemlere çözüm sağlayan, tekrarlanabilir ve test edilmiş yaklaşımlar olarak bildiğimiz tasarım desenlrinden biri olan singleton tasarım desenini, neden ve nasıl kullanıldığını ve beraberinde getirdiği sorunları göreceğiz.

Öncelikle singleton tasarım deseni creational patterns olarak sınıflandırılan gruba aittir. Yani, bu desen nesnelerin oluşturulmasıyla ilgilenir.

Bu yaklaşımın kullanılmasındaki temel amaç, tüm program boyunca hedef sınıftan tek bir nesne üretilip, bu nesneye gloabl bir erişim sağlanmasıdır.

Bu desen çoğunlukla bir uygulama içinde tek bir veritabanı bağlantısı, özel yapılandırma ayarları veya belirli bir kaynak üzerinde tek bir noktadan erişim gerektiren durumlarda kullanılır.

Avantajları;

  • Tek noktadan erişim: bir kaynağa veya servise tek bir erişim noktası sağlamış olur
  • Yeniden kullanılabilirlik: üretilen tek bir örnek uygulama içerisinde tekrar tekrar kullanılabilir ve bu durum kaynak tüketimini minimize eder
  • Kontrollü oluşturma: örneğin oluşturulmasının kontrollü şekilde ele alınmasını sağlar
  • Lazy Initialization: örnek yalnızca kullanım gerekliliği durumunda oluşturulur. Bu nedenle uygulamanın başlatılma süresi ve bellek tüketimi azaltılır

Singleton bir sınıfı nasıl implement edebileceğimize bakalım.

Nasıl Uygulanır?

Structure
  • Singleton örneğini tutması için sınıfa private bir field oluşturun.
  • Singleton örneğini almak için genel bir statik metod oluşturun.
  • Statik metodun içine “lazy initialization” uygulayacağız. İlk çağrıldığında yeni bir nesne oluşturmalı ve onu statik fielda vermelidir. Metod tüm çağrılarda her zaman bu örneği döndürmeli.
  • Sınıfın constructor bloğunu private yapın. Sınıfın statik metodu yine de constructorı çağırabilecektir ancak diğer nesneleri çağıramayacaktır.
  • Client kodunda tüm istekleri static metod üzerinden yapın. Böylede her seferinde tek bir nesneye erişmiş olacağız.
public class Singleton {

//değişken
private static Singleton _instance;

//private constructor
private Singleton(){}

//global erişim için get metodu
public static Singleton GetInstance() {

if(_instance==null)
_instance= new Singleton();

return _instance;
}
}

Burada newleme işleminin static get metodu içerisinde ve instance kontrolü yapılarak oluşturulması bize lazy initialization sağlar.

Program.cs içerisinde Singleton objelerimizi oluşturup bakalım.

 // The client code.
Singleton s1 = Singleton.GetInstance();
Singleton s2 = Singleton.GetInstance();

if (s1 == s2)
{
Console.WriteLine("İki değişken de aynı instanceı tutuyor.");
}
else
{
Console.WriteLine("Değişkenler farklı instanceları tutuyor.");
}

Output:

İki değişken de aynı instanceı tutuyor.

Multithread bir ortamda çalışıyorsak yukarıdaki çözüm bize beraberinde bir sorun da getirir. Çalışan birden fazla thread aynı sınıftan birden fazla örnek oluşturabilir. Bu yüzden static get metodunu thread safe hale getirmemiz gerekir.

Bu sorunu için lock kullanarak çözebiliriz.

  class Singleton
{
private Singleton() { }

private static Singleton _instance;

//lock object
private static readonly object _lock = new object();

public static Singleton GetInstance(string value)
{
if (_instance == null)
{
// ilk thread lock'u alıp devam edecek
// diğerleri lock alındığı için bekler
lock (_lock)
{
if (_instance == null)
{
_instance = new Singleton();
_instance.Value = value;
}
}
}
return _instance;
}

public string Value { get; set; }
}

Program.cs dosyasında kodumuzu test edersek

//client code
Thread process1 = new Thread(() =>
{
Test("process 1");
});

Thread process2 = new Thread(() =>
{
Test("process 2");
});

process1.Start();
process2.Start();
process1.Join();
process2.Join();

public static void Test(string value){
Singleton singleton = Singleton.GetInstance(value);
Console.WriteLine(singleton.Value);
}

Output:

process 1
process 1

SONUÇ

Ne Zaman Kullanılmalı?

  • Programınızdaki bir sınıfın tüm clientlar için yalnızca tek bir örneğe sahip olması gerektiğinde Singleton desenini kullanırız; örneğin, programın farklı bölümleri tarafından paylaşılan tek bir veritabanı nesnesi.
  • Global değişkenler üzerinde daha sıkı kontrole ihtiyaç duyduğumuzda Singleton desenini kullanırız.

Singleton tasarım deseni, doğru ve ihtiyaçlarınıza uygun bir şekilde uygulandığında çok güçlü bir araç olabilir, ancak gereksiz yere kullanıldığında kod karmaşıklığına yol açabilir. Bu nedenle Singleton kullanmadan önce, uygulamanızın ihtiyaçlarını ve tasarımını dikkatlice değerlendirmeniz önemlidir.

Sign up to discover human stories that deepen your understanding of the world.

Özge Odabaş
Özge Odabaş

Written by Özge Odabaş

Merhaba! Ben Özge. Junior Java Developerım. Kendimi geliştirirken edindiğim bilgileri yazıyorum. Keyifli okumalar.

No responses yet

Write a response