Yazılım mühendisliÄŸinin sanatsal yönü ağır olan “design pattern” kavramını bir çoÄŸumuz mutlaka duymuÅŸuzdur, ama rutin iÅŸlerimizden kendimizi boÅŸa çıkarıp bir türlü inceleme fırsatı bulamamışızdır, Bu ve bundan sonraki bir kaç makalelik dizide size kendi terminolojik yapısı içinde deyimleÅŸmiÅŸ olan “design pattern” yani “desen tasarımı” kavramını açıklamaya çalışacağım. Elbette açıklamalarımı en çok bilinen tasarım desenleri ile destekleyeceÄŸim. Bu konudaki ilk makalede en basit ve en popüler tasarım desenlerinden biri olan “Singleton” deseninden bahsedip “pattern design” sanatına daha farklı bir bakış açısıyla yaklaÅŸmanızı saÄŸlamaya çalışacağım. O halde iÅŸe basit tanımlarla baÅŸlayalım.
“Design Pattern” Nedir ?
BildiÄŸiniz üzere günümüzde yazılım mühendisliÄŸi alanında en fazla ses getiren kurgu yazılımın gerçek dünya ile olan iliÅŸkisinin saÄŸlanabilmesidir. Bu iliÅŸki elbette nesne yönelimli programlama tekniÄŸi ile saÄŸlanmaktadır. Nesne yönelimli programlama tekniÄŸi bilgisayar uygulamalarını soyut bir olgudan çıkararak insanların daha kolay algılayabileceÄŸi hale getirmiÅŸtir. Öyle görünüyorki, makro düzeyde gerçek hayatı modelleme ile baÅŸlayan bu iliÅŸki mikro düzeydede büyük ses getirecektir. Nitekim son yıllarda geliÅŸtirilen yapay sinir aÄŸları ile makinelerin çalışma sistemlerinin gün geçtikçe insanların veya canlıların çalışma ÅŸekline yaklaÅŸtığı görülmektedir. Artık bilgisayarlardan sadece verilen komutları yerine getirmek deÄŸil, belirli olaylar ve durumlar karşısında bazı hükümlere varabilmeleride istenmektedir. Burada vurgulamak istediÄŸim nokta ÅŸudur : bizler yazılım mühendisleri veya programcılar olarak gerçek hayatı ne kadar iyi modelleyebiliyorsak o kadar baÅŸarılı sayılırız. Peki “desgin pattern” konusu nerede devreye girmektedir? İşte benimde gelmek istediÄŸim nokta budur; “desgin patterns” bir modelin tasarımın ustaca tasarlanmasını saÄŸlayacak çeÅŸitli desenlerin oluÅŸturulmasını ve bu desenlerin ihtiyaç dahilinde herhangi bir modelin inÅŸaasında kullanılabilmesini saÄŸlar. “Design pattern” kavramı bir kurallar topluluÄŸundan ziyade bir iÅŸi nasıl ve en güzel ne ÅŸekilde yapabileceÄŸimiz gösteren yöntemler topluluÄŸudur. Öyleki iyi bir yazılım modelleyicisiyseniz kendi tasarım desenlerinizi oluÅŸturabilir ve bunları diÄŸer ustaların kullanımına sunabilirsiniz. Tasarım desenleri tecrübe ile oluÅŸturulan yapılardır. Bazıları olmazsa olmaz yapılar olmasına raÄŸmen bazıları tamamen yazılımın sanatsal yönünü göstermek için tasarlanmıştır . ÖrneÄŸin bu yazımın ana konusunu belirleyen “Singleton” tasarım deseni yıllardan beri bir çok kiÅŸi tarafından kullanılmıştır. Sizde bu yazıda bu desenin amacını ve nasıl uygulandığını öğrendiÄŸinizde eminimki projelerinizde mutlaka kullanacaksınız. Hemen ÅŸunuda belirteyimki bu tasarım deseni sizi uzaya götürmeyecektir, bu yüzden beklentilerinizi biraz daha azaltmanızda fayda var.
O halde “design pattern” yada “tasarım deseni” ni ÅŸu ÅŸekilde tanımlayabiliriz : Bir tasarım problemini en basit ve en efektif bir ÅŸekilde çözüme kavuÅŸturacak yöntemdir.
“Design Pattern” Kaynakları
“Design Pattern” konusunda yazılmış en güzel ve en popüler kaynaklardan biri Erich Gamma, Richard Helm, Ralph Johnson ve John Vlissides tarafından kaleme alınmış “Design Patterns: Elements of Reusable Object-Oriented Software“ kitabıdır. Bu kitapta en popüler tasarım desenleri anlatılmış ve bu desenlerin çeÅŸitli uygulamalarına yer verilmiÅŸtir. “Desgin pattern” guru’ları olarak anılan bu 4 kiÅŸi “Gangs Of Four(GOF)” olarak ta bilinmektedir. Zaten bahsi geçen kitapta anlatılan tasarım desenlerine de genel olarak GoF tasarım desenleri denilmektedir. Bu yazı ile baÅŸlayan yazı dizisinde GOF olarak anılan tasarım desenlerini sizlere aktarıp çeÅŸitli kullanım alanlarını açıklayacağım.
GOF tasarım desenleri genel olarak 3 ana grup altında incelenir. Bu gruplar ve herbir gruptaki tasarım desenlerinin isimleri aşağıda verilmiştir.
1 – Creatinal Patterns Bu desenler bir yada daha fazla nesnenin oluÅŸturulması ve yönetilmesi ile ilgilidir. ÖrneÄŸin bu yazıda anlatacağım ve bir uygulamanın ömrü boyunca belirli bir nesneden sadece bir adet bulunmasını garantileyen Singleton deseni bu gruba girmektedir. Bu gruptaki diÄŸer desenler ise
· Abstract Factory
· Builder
· Factory Method
· Prototype
 olarak bilinmektedir. Bu desenlerin bir çoğunu ilerleyen yazılarımda ele alacağım. Şimdilik sadece bir giriş yapıyoruz.
2 - Behavioral Patterns Bu gruptaki desenlerin amacı belirli bir işi yerine getirmek için çeşitli sınıfların nasıl birlikte davranabileceğinin belirlenmesidir. Bu gruptaki desenler ise aşağıdaki gibidir.
· Chain of responsibility
· Command
· Interpreter
· Iterator
·  Mediator
· Memento
· Observer
· State
· Strategy
· Template method
· VisitorÂ
3 - Structural Patterns Bu gruptaki desenler ise çeşitli nesnelerin birbirleri ile olan ilişkileri temel alınarak tasarlanmıştır. Bu gruptaki tasarım desenleri ise şunlardır:
· Adapter
· Bridge
· Composite
· Decorator
· Façade
· Flyweight
· Proxy
Bu giriÅŸ bilgisinden sonra ÅŸimdi nesnelerin yaratılması ile ilgili grup olan “Creatinal Patterns” grubunda bulunan ”Singleton” desenini açıklamaya baÅŸalayabiliriz.
Singleton Deseni
Singleton deseni bir programın yaşam süresince belirli bir nesneden sadece bir örneğinin(instance) olmasını garantiler. Aynı zamanda bu desen, yaratılan tek nesneye ilgili sınıfın dışından global düzeyde mutlaka erişilmesini hedefler. Örneğin bir veritabanı uyglaması geliştirdiğinizi düşünelim. Her programcı mutlaka belli bir anda sadece bir bağlantı nesnesinin olmasını isteyecektir. Böylece her geretiğinde yeni bir bağlantı nesnesi yaratmaktansa varolan bağlantı nesnesi kullanılarak sistem kaynaklarının daha efektif bir şekilde harcanması sağlanır. Bu örnekleri dahada artırmak mümkündür. Siz ne zaman belli bir anda ilgili sınıfın bir örneğine ihtiyaç duyarsanız bu deseni kullanabilirsiniz.
Peki bu işlemi nasıl yapacağız.? Nasıl olacakta bir sınıftan sadece ve sadece bir nesne yaratılması garanti altına alınacak? Aslında biraz düşünürseniz cevabını hemen bulabilirsiniz! Çözüm gerçekten de basit : statik üye elemanlarını kullanarak.
Singleton tasarım desenine geçmeden önce sınıflar ve nesneler ile ilgili temel bilgilerimizi hatırlayalım. Hatırlayacağınız üzere bir sınıftan yeni bir nesne oluşturmak için yapıcı metot(constructor) kullanılır. Yapıcı metotlar C# dilinde new anahtar sözcüğü kullanılarak aşağıdaki gibi çağrılabilmektedir.
Sınıf nesne = new Sınıf();
Bu ÅŸekilde yeni bir nesne oluÅŸturmak için new anahtar sözcüğünün temsil ettiÄŸi yapıcı metoduna dışarıdan eriÅŸimin olması gerekir. Yani yapıcı metodun public olarak bildirilmiÅŸ olması gerekir. Ancak “Singleton” desenine göre belirli bir anda sadece bir nesne olabileceÄŸi için new anahtar sözcüğünün ilgili sınıf için yasaklanması gerekir yani yapıcı metodun protected yada private olarak bildirilmesi gerekir. EÄŸer bir metodun varsayılan yapıcı metodu(default constructor- parametresiz yapıcı metot) public olarak bildirilmemiÅŸse ilgili sınıf türünden herhangi bir nesnenin sınıfın dışında tanımlanması mümkün deÄŸildir. Ancak bizim isteÄŸimiz yalnızca bir nesnenin yaratılması olduÄŸuna göre ilgili sınıfın içinde bir yerde nesnenin oluÅŸturulması gerekir. Bunu elbette statik bir özellik(property) yada statik bir metotla yapacağız. Bu statik metot sınıfın kendi içinde yaratılan nesneyi geri dönüş deÄŸeri olarak bize gönderecektir. Peki bu nesne nerde ve ne zaman yaratılacaktır? Bu nesne statik metodun yada özelliÄŸin içinde yaratılıp yine sınıfın private olan elemanına atanır. Tekil olarak yaratılan bu nesne her istendiÄŸinde eÄŸer nesne zaten yaratılmışsa bu private olan elemanın referasına geri dönmek yada nesneyi yaratıp bu private deÄŸiÅŸkene atamak gerekmektedir. Sanırım bu deseni nasıl uygulayabileceÄŸimizi kafanızda biraz canlandırdınız. O halde daha fazla uzatmadan desenimizi uygulamaya geçirelim.
Singleton Deseninin 1. versiyonu
public class SingletonDeseni
{
     private static SingletonDeseni nesne = new SingletonDeseni();Â
     private SingletonDeseni()Â
     {
     }Â
     public static SingletonDeseni Nesne
     {Â
          getÂ
          {Â
               return nesne;Â
          }Â
     }
}
|
Yukarıdaki sınıf örneğinde SingletonDeseni sınıfı belleğe yüklendiği anda statik olan SingletonDeseni nesnesi yaratılacaktır. Bu nesne yaratılışının new anahtar sözcüğü ile yapıldığına dikkat edin. Eğer siz Main() gibi bir metodun içinden bu nesneyi yaratmaya kalksaydınız derleme aşamasında hata alırdınız. Çünkü public olan herhangi bir yapıcı metot bulunmamaktadır. Ayrıca
Siz Main() gibi bir metodun içinden yaratılan bu nesneye
SingletonDeseni nesne = SingletonDeseni.Nesne;
şeklinde erişmeniz mümkündür. Böylece yukarıdaki deyimi her kullandığınızda size geri dönen nesne, sınfıın belleğe ilk yüklendiğinde yaratılan nesne olduğu garanti altına alınmış oldu. Dikkat etminiz gereken diğer bir nokta ise nesneyi geri döndüren özelliğin yalnızca get bloğunun olmasıdır. Böylece bir kez yaratılan nesne harici bir kaynak tarafından hiç bir şekilde değiştirilemeyecektir.
Yukarıdaki SingletonDeseni sınıfını aşağıdaki gibi de yazmamız mümkündür.
Singleton Deseninin 2. versiyonu
public class SingletonDeseni
{
     private static SingletonDeseni nesne = new Singleton();Â
     private SingletonDeseni()Â
     {
     }Â
     public static Singleton Nesne()
     {Â
         return nesne;Â
     }
}
|
Dikkat ederseniz iki sınıfın tek farkı oluşturulan nesneye erişme biçimidir. İlk versiyonda nesneye özellik üzerinden erişilirken ikinci versiyonda metot üzerinden erişilmektedir. Değişmeyen tek nokta ise her iki erişim aracının da statik olmasıdır.
Yukarıdaki her iki versiyonda da biz yaratılan nesneyi
SingletonDeseni nesne = SingletonDeseni.Nesne;
yada
SingletonDeseni nesne = SingletonDeseni.Nesne();
şeklinde istediğimizde nesne zaten yaratılmış durumda olmaktadır. Oysa bu sınıfı daha efektif bir hale getirerek yaratılacak nesnenin ancak biz onu istediğimizde yaratılmasını sağlayabiliriz. Bu durumu uygulayan Singleton deseninin 3 versiyonunu olarak aşağıda görebilirsiniz.
Singleton Deseninin 3. versiyonu
public class SingletonDeseni
{
     private static SingletonDeseni nesne;Â
     private SingletonDeseni()Â
     {
     }Â
     public static Singleton Nesne()
     {Â
         if(nesne == null)
              nesne = new SingletonDeseni();
         return nesne;Â
     }
}
|
Gördüğünüz üzere nesne ilk olarak sınıf belleğe yüklendiğinde değilde o nesneyi ilk defa kullanmak istediğimizde yaratılıyor. İlgili nesneyi her istediğimizde yeni bir nesnenin yaratılmaması içinde
if(nesne == null)
şeklinde bir koşul altında nesnenin yaratıldığına dikkat edin.
Not : 3.versiyonda nesneyi yaratan bir metot olabileceği gibi 1. versiyondaki gibi sadece get bloğu olan özellikte olabilir.
Herşeye rağmen yukarıdaki 3 versiyonda  bazı durumlar için tek bir nesnenin oluşmasını garanti etmemiş olabilirz. Eğer çok kanallı(multi-thread) bir uygulama geliştiriyoırsanız farklı kanalların aynı nesneyi tekrar yaratması olasıdır. Ancak eğer çok kanallı çalışmıyorsanız(çoğunlukla tek thread ile çalışırız) yukarıdaki sade ama öz olan 3 versiyondan birini kullanabilirsiniz. Ama eğer çok kanallı programlama modeli söz konusu ise ne yazıkki farklı kanalların aynı nesneden tekrar yaratmasını engelemek için ekstra kontroller yapmanız gerekmektedir. Ne yazıkki diyorum çünkü bu yapacağımız kontrol performansı büyük ölçüde düşürmektedir.
O halde çok kanallı uygulamalarda kullanabileceğimiz Singleton desenini yazalım.
Singleton Deseninin 4. versiyonu
public class SingletonDeseni
{
     private static SingletonDeseni nesne;Â
     private static Object kanalKontrol = new Object;Â
     private SingletonDeseni()Â
     {
     }Â
     public static Singleton Nesne()
     {Â
         if(nesne == null)
         {
              lock(kanalKontrol)
              {
                    if(nesne == null)
                   {
                           nesne = new SingletonDeseni();
                   }
              }
         }
          return nesne;Â
     }
}
|
Yukarıdaki desendeki püf nokta lock anahtar sözcüğünün kullanımıdır.Eğer nesne ilk defa yaratılcaksa yani daha önceden nesne null değere sahipse lock anahtar sözcüğü ile işaretlenen blok kitlenerek başka kanalların bu bloğa erişmesi engellenir. Böylece kilitleme işlemi bittiğinde nesne yaratılmış olacağı için, kilidin kalkmasını bekleyen diğer kanal lock bloğuna girmiş olsa bile bu bloktaki ikinci if kontrolü nesnenin yeniden oluşturulmasını engelleyecektir. Böylece çok kanallı uygulamalar içinde tek bir nesnenin oluşmasını ve bu nesneye erişimi garanti altına alan Singleton desenini tasarlamış olduk.
Son olarak lock anahtar sözcüğünü kullanmadan çok kanallı uygulamalar içinde tek bir nesneyi garanti altına alacak deseni yazalım. Aşağıda Singleton desenin 5. versiyonu bulunmaktadır.
Singleton Deseninin 5. versiyonu
public class SingletonDeseni
{
     private static SingletonDeseni  nesne = new SingletonDeseni ();Â
     private static SingletonDeseni()Â
     {
     }Â
     private SingletonDeseni()Â
     {
     }Â
     public static SingletonDeseni  Nesne
     {Â
          getÂ
          {Â
               return nesne;Â
          }Â
     }
}
|
Bu versiyonun birinci versiyondan tek farkı yapıcı metodunda statik olmasıdır. C# dilinde statik yapıcı metotlar bir uygulama domeninde ancak ve ancak bir nesne yaratıldığında yada statik bir üye eleman referans edildiğinde bir defaya mahsus olmak üzere çalıştırılır. Yani yukarıdaki versiyonda farklı kanalların(thread) birden fazla SingletonDeseni nesnesi yaratması imkansızdır. Çünkü static üye elemanlar ancak ve ancak bir defa çalıştırılır.
Son versyion basit ve kullanışlı görünmesine rağmen kullanımının bazı sakıncaları vardır. Örneğin Nesne Özelliği dışında herhangi bir statik üye elemanınız var ise ve ilk olarak bu statik üye elemanını kullanıyorsanız siz istemedğiniz halde SingletonDeseni nesnesi yaratılacaktır. Zira yukarıda da dediğimz gibi bir statik yapıcı metot herhangi bir statik üye elemanı kullanıldığı anda çalıştırılır. Diğer bir sakıncalı durumda birbirini çağıran statik yapıcı metotların çağrılması sırasında çelişkilerin oluşabileceğidir. Örneğin her static yapıcı metot ancak ve ancak bir defa çalıştırılır dedik. Eğer çalıştırılan bir static metot diğer bir statik metodu çağırıyor ve bu statik metotta ilkini çağırıyorsa bir çelişki olacaktır.
Kısacası eğer kodunuzun çelişki yaratmayacağından eminseniz 5. deseni kullanmanız doğru olacaktır. Eğer çok kanallı uygulama geliştiriyorsanız 4. versiyonu, çok kanallı uygulama geliştirmiyorsanızda 3. versiyonu kullanmanız tavsiye edilmektedir.
Yorumlar
Yorum Yok
Yorumunuzu Ekleyin
Yorum eklemek için giris yapmalısınız.