Singleton Design Pattern - Nesne Yönelimli Programlama Tasarım Desenleri

Singleton tasarım deseni obje yönelimli programlama dillerinde yazılan bir sınıfın, çalışma zamanında kesinlikle sadece bir kez örneklenmesini garanti altına alır. Singleton olarak tasarlanmış bir sınıftan sadece bir nesne üretebilirsiniz, sonraki çağırılarınızda daima önceden üretmiş olduğu nesneyi geri döndürür.

Bir sınıfın Singleton olabilmesi için onu doğru şekilde implemente edilmesi çok önemlidir. Singleton sınıfların contructer'ı gizli(private) tanımlanmalıdır. Böylece çağırılırken new() anahtar kelimesiyle kullanılması önlenmiş ve birden fazla obje oluşturulmasının önüne geçilmiş olur. Private contructer'a sahip sınıflar sadece kendi içinde örnekleme gerçekleştirebilir.

Şimdi Singleton tasarım prensibinin doğru şekilde kullanımına kod üzerinde bir göz atalım. Her ne kadar örnek kod C# ile yazılmış olsa da java ve diğer obje yönelimli programlama dillerinde de ufak değişikliklerle kullanılabilir.


Singleton Sınıf Tanımı

Daha önce de belirttiğimiz gibi, Singleton sınıflar private constructer'a sahip olmalıdır. Böylece bu sınıfı kullanmaya çalışan diğer sınıflar, nesne oluşturamazlar. Nesne oluşturma işlemini biz bizzat gerçekleştirerek kaç adet instance oluşturulduğunu kontrol altında tutabiliriz.

public class SingletonClass
{
 private static SingletonClass nesne;
 private SingletonClass() { }
}

Şimdi sınıfın içinde oluşturulacak nesneye dışarıdan kontrollü bir şekilde erişilebilmesini sağlamamız gerekiyor. Kodu düzenleyerek gerekli değişiklikleri yapalım.

public class SingletonClass
{
        private static SingletonClass nesne;

        private SingletonClass() { }

        public static SingletonClass Nesne
        {
            get
            {
                if (nesne == null)
                {
                    nesne = new SingletonClass();
                }
                return nesne;
            }
        }
}

Kodun her satırının ne yaptığını daha detaylı bir şekilde inceleyeceğiz ancak öncelikle büyük resme bir bakalım. Şu anda bir erişim belirteci yazmış olduk ve içerideki nesneye erişilmeye çalışıldığında zaten bir nesne oluşturulup oluşturulmadığını denetliyoruz. Singleton class tasarımı temelde bu kadardır. Ancak bu kod bazı sorunlara karşı açık durumda.

Şu anki yaklaşımla ilgili sorun nedir?

Aslında hiçbir şey. Geliştirdiğiniz program single-thread ise yani aynı anda tek bir işlem parçacığı kullanıyorsa sorunsuz çalışacaktır. Ancak eğer multi-thread bir program geliştiriyorsanız, birden fazla thread'in aynı anda bu sınıfa erişmeye çalışması çoklu örneklemeye neden olabilir ki bu da Singleton tasarım desenine aykırıdır. 

Peki sorunu nasıl çözebiliriz?

Az önce yazdığımız kod üzerinde gerçekleştireceğimiz küçük bir optimizasyon ile bu durumun üstesinden gelebiliriz. Nesne'nin boş olup olmadığını kontrol ederken bloğu kilitleyerek aynı anda bir den fazla thread'in erişmesini kolayca önleyebiliriz. Aşağıda kodun tamamen düzeltilmiş halini görebilirsiniz.


  // Singleton sınıfını tanımlayalım
    public class SingletonClass
    {
        // Sınıf ilk kez nesneye dönüştürüldükten sonra
        // statik olarak "nesne" alanında saklanacak.
        // Sonraki erişimlerde her zaman bu nesne döndürülecektir.
        private static SingletonClass nesne;

        // Kilitleyici objeyi yarattık
        private static object kilit = new object();

        // Sınıfın constructer'ını gizleyerek new anahtar sözcüğü
        // ile nesne alınmasını önlüyoruz. Böylece birden fazla
        // nesne yaratılmasının da önüne geçmiş oluyoruz
        private SingletonClass() { }

        // Sınıfa ait nesnenin uzaktan kontrollü erişimini sağlıyoruz
        public static SingletonClass Nesne
        {
            get
            {
                // Daha önce örnekleme yapılmış mı?
                // Eğer daha önce zaten örneklenmişse aşağıdaki if
                // bloğuna hiç girilmeyerek aynı nesne geri
                // döndürülecektir.
                if (nesne == null)
                {
                    // Burada kodu diğer threadlerin kullanımına kilitliyoruz
                    lock (kilit)
                    {
                        if (nesne == null)
                        {
                            // Daha önce örnekleme yapılmadığına göre 
                            // şimdi bir nesne üretebiliriz
                            nesne = new SingletonClass();
                        }
                    }
                }
                return nesne;
            }
        }
    }

lock() anahtar kelimesini kullanarak o blok üzerinde sadece bir thread'in ulaşabilmesini sağlıyoruz. Olur da nesneye iki thread aynı anda erişmeye çalışırsa biri kilitlenecektir ancak kilit açıldığı anda kaldığı yerden devam edeceği için, nesnenin boş olup olmadığına dair kontrolü yeniden yapmalıyız.

İşte bu kadar. Gördüğünüz gibi SingletonClass implementasyonu oldukça kolay. Peki artık new() sözcüğüyle çağıramıyorsak nasıl erişeceğiz? Tıpkı statik sınıflarda olduğu gibi:

SingletonClass tekilSinif = SingletonClass.Nesne;




Singleton sınıf nasıl kullanılır?

WinForms kullanarak bu sınıfı nasıl kullanabileceğimize bir bakalım. Ekrana sadece bir buton koymanız yeterli. Butonun Click() olayını yaratın. Kalan işimiz arkaplan kodu ile.


Arkaplan kodu ise aşağıdaki gibi. (Sadece mesaj kutularını ekledik ve butonu, sınıfı çağıracak şekilde programladık)


Şimdi programı çalıştırıp test edebiliriz.

 public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            SingletonClass tekilSinif = SingletonClass.Nesne;
        }
    }

    public class SingletonClass
    {
        private static SingletonClass nesne;
        private static object kilit = new object();

        private SingletonClass() { }

        public static SingletonClass Nesne
        {
            get
            {
                if (nesne == null)
                {
                    lock (kilit)
                    {
                        if (nesne == null)
                        {
                            nesne = new SingletonClass();
                            MessageBox.Show("Sınıf ilk kez yaratıldı.");
                        }
                    }
                }
                else
                {
                    MessageBox.Show("Sınıf zaten yaratılmış. Yaratılan geri döndürülüyor.");
                }
                return nesne;
            }
        }
    }

Butona ilk kez tıkladığınızda "Sınıf ilk kez yaratıldı" sonraki her tıklamanız da ise "Sınıf zaten yaratılmış. Yaratılan geri döndürülüyor" mesajını almanız gerekiyor.

Singleton sınıfları nerde kullanabilirsiniz.

Singleton kullanımına .NET kütüphaneleri içinde çok sık kullanılmasa da obje yönelimli programlama desenleri arasındadır. Kullanılmak istendiğinde doğru şekilde implemente edilmesi önemlidir. Geliştirdiğiniz programda bir objeden sadece ama sadece bir tane yaratılması gerektiğinden emin olduğunuz durumlarda kullanabilirsiniz.


Bazı önemli noktalar

Singleton sınıflardan sınıf türetilemez. Constructer'ı private olarak tanımladığımız için base class olarak kullanılması olanaksız olur. 

Yorumlar



Bu blogdaki popüler yayınlar

C# LAN üzerinde TCP Bağlantısı ile Veri Aktarımı (Konsol)

Android Programlama: EditText Kullanarak Kullanıcıdan Girdi Almak

Android Programlama: Button Kullanımı & Event Ekleme