Singleton Design Pattern
Merhaba sevgili dostlar!
Bu yazımda, Yaratımsal Tasarım Desenleri (Creational Design Pattern) kategorisinde bulunan Singleton Design Pattern konusunu ele alacağım. Hani şu, ne kadar “tasarım desenleri” eğitimi alırsanız alın, kaç tane makale okursanız okuyun, aklınızda en fazla kalacak desenden bahsediyorum: Singleton Design Pattern.
Daha önceki tasarım deseni makalelerinde olduğu gibi, önce problemin ne olduğunu anlamamız gerekiyor. Uygulamanızda kullanacağınız nesneden yalnızca bir tane yaratılmasını istiyorsanız, bunu nasıl çözersiniz? Fakat bundan önce belki de şu soruyu yanıtlamamız gerekebilir; neden bir nesneden yalnızca bir adet üretilmesini isteyelim ki?
Singleton Design Pattern – Giriş
Eğer bir nesnenin yapacağı işlemler, sadece ve sadece parametrelere bağlı olarak değişiyorsa; o nesneden birkaç tane üretmenin bir anlamı var mıdır? Unutmayın ki üretilen her nesne bellekte bir yer işgal etmekte. Ve siz, tamamen aynı işleve sahip onlarca nesne üretiyorsanız, bu fazla kaynak tüketimine sebep olacaktır. Bu noktada aklınıza şu gelebilir: “İyi de benzer bir amaçla static class kullanabilirim, neden yalnızca bir kere üretilen bir nesne var edeyim ki?” Bu soruyu soruyorsanız gerçekten çok haklısınız ama yazının sonunda aradığınız cevaba ulaşacaksınız.
İşte bu kaynak tüketimini engellemek için “bana bir tane yeter ya” deşiğiniz nesneleri singleton design pattern ile oluşturacağız. Şimdi tabii bu konuda verilmesi gereken bir günlük hayat örneği var elbette. Evinizde, yalnızca bir tane olmasının yeterli olduğu nesneleri düşünün. Çamaşır makinesi, buzdolabı… Beyaz eşyaların hemen hepsinin bir tane olması yeterli oluyor. “Bizim eve ikinci bir çamaşır makinesi gereksiz” diyorsanız, işte o nesne singleton olarak üretilebilir.
O zaman, artık kod örneğine geçebiliriz. Önce bir senaryo oluşturalım her zamanki gibi. Bir uygulamada, doğrudan DB ile çalışacak bir ADO.NET yardımcı sınıfı yazmaya karar verdiniz. Uygulamanızdan veritabanına gidecek her talep (request), aynı adımlar kullanılarak işlenebilir. O halde, bu sınıftan yalnızca bir instance alabiliyor olmam yeterli olacaktır. Peki, kod tarafında bir sınıftan yalnızca bir nesne üretilmesini nasıl sağlarız? Nesne üretimi için sınıfın Constructor üyesine erişim gerektiğine göre, ilk olarak Constructor erişimini kısıtlamamız gerekiyor. Hadi kodlamaya başlayalım.
Gördüğünüz gibi, (18. Satırda) DBHelper
sınıfının Constructor üyesini private olarak belirledim. Artık new anahtar sözcüğünü kullanarak nesne üretilemeyecek. O halde, instance alabilmek için public erişim düzenleyicisi ile tanımlanmış static bir metot geliştirmem gerekiyor şimdi. Bu sınıftan, yalnızca bir tane nesne üretilmesini istediğimize göre, gerekli denetlemeyi de bu metot yapmalı o zaman.
Denetlemeden ne kastettiğimi biraz daha açıklamak istiyorum. Yazacağımız metot, sadece bir kez Constructor’a erişmeli. Mantıksal olarak şöyle diyebilirim bu durumda: “Eğer daha önce hiç DbHelper nesnesi üretilmemiş ise nesneyi üret ve sonra bu nesneyi döndür.”
Demek ki, daha önce nesne üretilip üretilmediğini denetlemem gerekiyor. Bunu da, static bir alandan (field) faydalanarak yapıyorum.
Tüm bunlar kodda nasıl gözüküyor peki? Tüm sınıfı bir kez daha görelim:
Örnekte yer alan 25. Satırda tanımlanan static alanı ve CreateDbHelper metodunda bu alanın nasıl kullanıldığını inceleyin lütfen. Bu arada, bu kullanıma da Lazy Initialization yöntemi dendiğini de belirteyim.
Evet, artık CreateDbHelper
metodu sayesinde, DBHelper sınıfından yalnızca bir kere instance alabiliyoruz. Bu arada fark ettiyseniz, sınıfımın içine StateMessage isimli bir özellik ekledim. Bunun sebebi de, nesnemizin sadece bir tane olup olmadığını test etmek. Hadi gelin görelim.
Sonuç:
Şimdi, bu noktaya kadar örneğimizi inceleyip uyguladıysanız, bir soru beyninizi kemirmeye başlayacaktır. Bu sınıfı singleton yapmak yerine, tüm sınıfı static yapmış olsaydım bundan ne farkı olurdu? Neden static yapabiliyorken singleton tercih edeyim ki?
Öncelikle hemen söyleyeyim; bu sınıfı (doğal olarak tüm üyelerini de) static yaparsanız, hiçbir dezavantajınız olmaz. Aynen istediğiniz gibi minimum kaynak tüketimiyle istediğiniz sonucu elde edersiniz.
Peki o zaman neden singleton yapalım?
Lütfen hayal edin. Yukarıda yazdığımız DBHelper sınıfının (static olmayan) üyeleri bir interface’den alınabilir miydi? Kesinlikle evet ! Peki, static bir class bir interface’i implemente edebilir mi?
Asla! Bu imkansız! İşte bu nedenle, mecburen singleton pattern kullandığımız durumlar var. Kısaca şöyle özetleyebiliriz. Bir interface’i implemente eden, fakat proje döngüsünde sadece bir nesne üretmesi gereken sınıflar, singleton desenini kullanabilirler.
Evet sevgili tasarım deseni meraklısı dostlarım… Bu yazımız ile birlikte Yaratımsal Tasarım Deseni (Creational Design Pattern) kategorimizi tamamlamış oluyoruz.
Bir sonraki yazıda görüşmek üzere…
Abi Scala dışında hiç bir OO dilde guvenli singleton olusturamazsin senin orneginin bi nebze daha guvenlisi:
https://msdn.microsoft.com/en-us/library/ff650316.aspx
Tabi bu da guvenli degil cunku classtan bir nesneyi biri farkli bir code parcaciginda reflectionla uretirse senin kod calismadan baska bir nesne uretebiliyorsun ayni classtan yani singleton olmamis oluyor. Bir tek cozumu var class kullanmadan guvenli singleton yapmanin o da enum yapmak.
Turkay Bey elinize sağlık bütün yazılarınızı beğeniyle okudum.Açık ve espirili anlatımız da cabası.Sezar’ın hakkı Sezar’ a.