Merhaba Arkadaşlar,
Bu yazımızda Creational Patterns (Oluşturulma Tasarım Kalıpları) ailesinden Singleton Pattern (Tek Nesne Kalıbı)‘i inceleyeceğiz.
Kullanım Amacı
Singleton pattern’in kullanım amacı ortak kullanılan nesneleri bir kere oluşturarak maliyeti azaltmak ve performansı arttırmaktır. Singleton nesneler static olmaktadır. Uygulama ayağa kalktığında gelen ilk istekle Ram’de oluşur ve daha sonraki istekler ise ilk oluşturulan nesne üzerinden işlem yapmaya devam eder. Kullanım alanı olarak ilk başta da belirttiğimiz gibi projede ortak olarak kullanılan alarda kullanılır. Örneğin veri tabanı bağlantılarında, dosya işlemlerinde, loglama işlemlerinde, bildirimlerde, iş katmanı servislerimizde ve buna benzer birçok yerde kullanılmaktadır.
Singleton kalıbının kullanım sıklığı dofactory verilerine göre 4/5.
Örnek Kullanım:
İlk olarak singleton olmadan örneğimizi aşağıdaki gibi yazıp çalıştırıyoruz.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
using System; namespace Singleton { class Program { static void Main(string[] args) { for (var i = 0; i < 20; i++) Console.WriteLine(Singleton.CurrentGuid); Console.ReadLine(); } } class Singleton { private static string _currentGuid; public static string CurrentGuid { get { _currentGuid = Guid.NewGuid().ToString(); return _currentGuid; } } } } |
Çıktıda gördüğünüz gibi guid için farklı farklı değerler oluşturuyor. Eğer Guid değerinin her seferinde aynı değeri dönmesini istersek Guid değeri bir kere set edilecek ve diğer gelen isteklerde bu değer döndürülecek.
Singleten sınıfını aşağıdaki gibi düzenleyip tekrar sonucu inceleyelim.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
class Singleton { private static string _currentGuid; static object _lock = new object(); public static string CurrentGuid { get { lock (_lock) { if (_currentGuid != null) return _currentGuid; lock (_lock) { _currentGuid = Guid.NewGuid().ToString(); } return _currentGuid; } } } } |
Çıktıda listelenen değerlerin hepsinin aynı olduğunu görüyoruz. CurrentGuid property her çağrıldığında _currentGuid değerinin null olup olmadığı kontrol ediliyor. Eğer null değilse direkt ramde tutulan değer geri gönderiliyor. Eğer null ise değerimizi oluşturup geri gönderiyor ve bu istekten sonra ki tüm isteklerde bu değer gönderilecek şekilde ram de tutuluyor.
Singleton tasarım kalıbının amacı nesnenin bir kere oluşturulması olduğundan lock ile şöyle bir durumun önüne geçmeye çalıştık.
Bu nesne birden çok yerden aynı anda çağırılmış olabilir. null kontrolünü aynı anda geçen birden fazla istek olabilir ve her gelen istek null kontrolünü geçtiği için birden fazla nesne oluşturmuş olur. Bu da singleton amacına uymayacağı için gelen istekleri sıraya koyup bekletiyoruz. Aynı anda birden fazla istek geldiğinde ilk gelen istek lock bloğuna girecek ve diğer istekler sırasını bekleyecektir. İlk istek işlemi yaptıktan sonra nesnemiz null olmayacağı için sonraki istekler singleton amacına uygun olarak ilk oluşturulan değeri alıp işlemine devam edecektir.
Bu durum genelde değeri set ederken uzun süren işlemlerde meydana gelebiliyor. Örneğin çalıştığım bir e-ticaret sitesinde ürün fiyatllarını ram’de tutuyorduk. Fiyat tablosunda farklı müşteri segmentleri ve indirimleri olduğu içinyaklaşık 6 milyon kayıt bulunuyor. Bu kayıtlarla ilgili hesaplamaları yapıp Ram de tutuyorduk. Bu işlem yaklaşık 2 – 3 dk sürüyordu. Eğer burada singleton kullanmasaydık her ürün fiyatıyla ilgili işlemde 2 – 3 dakikalık bir bekleme olacaktı ki bu beklenilmesi kabul edilecek bir süre değil. Aynı şekilde lock deyimini kullanmasaydık ilk gelen istek henüz bitmeden başka bir istek geldiğinde tekrar fiyatları çekmeye çalışacaktı ve bu da can yakacak bir durum haline gelecekti.
Umarım yazı sizin için faydalı olmuştur.
Bir sonra ki makalemizde görüşmek üzere, hoşçakalın.