Tasarım örüntüleri
Tasarım desenleri, tasarım kalıpları, tasarım örüntüleri veya tasarım şablonları, çok rastlanan, birbirine benzer sorunları çözmek için geliştirilmiş ve işlerliği kanıtlanmış genel çözüm önerileridir.
Yazılım tasarım desenleri
Yazılım tasarım örüntüleri, yazılım tasarımı sırasında sıkça karşılaşılan, birbirine benzer sorunları çözmek için geliştirilmiş ve işlerliği kanıtlanmış genel çözüm önerileridir. Genel olarak yazılım tasarım örüntüleri programlama dillerinden bağımsız olarak tanımlansalar da, nesneye yönelimli programlama dillerine uygun yazılım tasarım örüntüleri daha çok bilinir. Bu örüntüler, nesneler ve sınıflar arasındaki ilişkileri ve etkileşimleri gösterirler. Programcı bir tasarım örüntüsünü elindeki soruna bakarak özelleştirip kullanabilir.
Tarihçe
Tasarım örüntülerinin temelleri Mimar Christopher Alexander'ın 1970 sonlarında başlatığı çalışmalara dayanmaktadır. Alexander 1977'de Bir Desen Dili: Şehirler, Binalar, Yapılar (İngilizce: A Pattern Language: Towns, Buildings, Construction, ISBN 0-19-501919-9), 1979'da Ebedî Yapım Yöntemi (İngilizce: A Timeless Way of Building, ISBN 0-19-502402-8) kitaplarını yayınlamıştır. Bu kitaplarda tasarın örüntülerinin üst seviyesi örüntüleri içeren mimarî desen örneklerinin yanı sıra desenlerin nasıl belgeleneceği de konu edilmiştir.
1987'deki uluslararası Nesneye Yönelik Programlama, Sistemler, Diller ve Uygulamalar (İngilizce: OOPSLA, Object Oriented Programming, Systems, Languages, and Applications) konferansına kadar desenlerle ilgili bir çalışma ortaya çıkmamış. Bu tarihten sonra ise Grady Booch, Richard Helm, Erich Gamma ve Kent Beck başta olmak üzere örüntülerle ilgili makale ve sunumlar yayınlamışlardır. 1994'te Erich Gamma, Richard Helm, Ralph Johnson ve John Vlissides tarafından yayınlanan Tasarım Örüntüleri: Tekrar kullanılabilir Nesneye Yönelik Yazılımın Temelleri (İngilizce: Design Patterns: Elements of Reusable Object-Oriented Software, ISBN 0-201-63361-2) tasarım örüntülerinin yazılımda kullanılmasında dönüm noktası olmuştur.
Dörtlü Çete (Gang of Four, kısaca GoF) yazılım tasarım desenleri
Yazılım tasarım örüntüleri 1994 tarihinde Tasarım Örüntüleri: Tekrar kullanılabilir Nesneye Yönelik Yazılımın Temelleri (İngilizce: Design Patterns: Elements of Reusable Object-Oriented Software, ISBN 0-201-63361-2) adıyla yayınlanan kitap ile yaygınlaşmaya başlamış. Kitabın yazarları Erich Gamma, Richard Helm, Ralph Johnson ve John Vlissides bilgisayar bilimleri çevresinde Dörtlü Çete olarak de bilinmektedir. Dörtlü Çete, isimi kitabın isminin uzun olmasından dolayı konuyla ilgili e-postalarda kısaltma yapılarak, yazarları kastederek, kitabın "Dörtlü Çetenin Kitabı" (İngilizce: Book of GoF) olarak anılmasıyla ortaya çıkmıştır.
Tasarım desenleri sınıfları
Dörtlü Çete'nin Tasarım Örüntüleri kitabı (ISBN 0-201-63361-2) tasarım örüntülerini üç sınıfa ayırır, fakat bu sınıfları birbirinden ayıran keskin kriterler yoktur.
Davranış örüntüleri
Davranış örüntüleri işlevsel sorumlulukların nesneler arasında nasıl atanacağı ve yazılımın gerektirdiği çözüm yöntemlerinin nesnelerce nasıl kullanılacağı hakkında öneriler sunar. Davranış örüntüleri nesne ve sınıf kalıpları yanı sıra nesneler arasındaki iletişim ile ilgili örüntüler de sunar. Davranış örüntüleri tasarımcının nesneler arası iletişim ve iletişim yöntemlerine yoğunlaşmasını sağlar.
Aynen yapısal örüntülerde olduğu gibi, davranış örüntüleri de ikiye ayrılır: sınıf davranış örüntüleri ve nesne davranış örüntüleri.
Sınıf davranış örüntüleri kalıtım kullanarak davranışların sınıflar arasında dağıtılmasını mümkün kılar. Nesne davranış örüntüleri ise nesne bileştirme yoluyla tek bir nesnenin kolayca sağlayamayacağı davranışların bir nesne grubu ile sağlanmasını mümkün kılar.
- Arabulucu (İngilizce: mediator pattern)
Birbiri ile bağlatılı olarak çalışan nesnelerin aynı çatı altında tutularak tek bir noktadan (yani ara bulucu tarafından) yönlendirilmesini mümkün kılar. Ara bulucuya bağlı olan nesneler, durum değişikliklerini ara bulucuya iletirler. Ara bulucu uygulamanın gerektirdiği düzenleme ve sıra ile ilgili nesnelerden isteklerde bulunur. Üst seviye kullanıcı nesneler ise sadece ara bulucu ile bağlantı kurarlar.
- Durum (İngilizce: state pattern)
Bir nesnenin davranışını durumuna göre değiştirmesine olanak sağlar. Kullanıcı açısından, nesne sınıfını değiştiriyormuş izlenimi verir. Uygulamanın gerektirdiği doğrultuda yeni davranışlar eklenip çıkarılmasına olanak sağlar. Kullanıcı nesneler ise bu tür değişikliklerden etkilenmez.
- Gözlemci (İngilizce: observer pattern)
Bir grup nesnenin, gözlemciler, gözlem altındaki bir nesnede olan değişimlerden otomatik olarak haberdar olmasına olanak sağlar. Gözlem altındaki nesne, kimler tarafından izlendiğinden bağımsız olarak işlevini sürdürür. Zaman içinde yeni gözlemcilerin katılımı ya da ayrılması mümkündür. Bu sayede uygulama zaman içinde davranış değiştirebilir.
- Kalıp yordamı (İngilizce: template method pattern)
Bir yordamın çözüm kalıbı olarak kullanılmasına olanak sağlar. Kalıp üzerindeki bazı işlem adımları alt sınıflar tarafından işlenmesine olası kılar. Dolayısıyla ana kalıp değişmeksizin, bazı ara adımlar değişikliğe uğratılabilir. Kullanıcılar bu değişikliklerin farkında olmazlar.
- Komut (İngilizce: command pattern)
Kullanıcı (nesnel) isteklerinin nesnelere dönüştürülerek işlenmesini olası kılar. Bu sayede farklı kullanıcıların istekleri nesnel kayıtlara dönüştürülerek kuyruk ya da kayıtlarda tutulabilir. Bu sayede yapılan işlemlerin geriye dönüştürülmesine de imkân verilir.
- Sorumluluklar zinciri (İngilizce: chain of responsibility pattern)
Bir kullanıcı (nesnel) isteğinin birden fazla nesne tarafından değerlendirilerek karşılanmaya çalışılmasına olanak sağlar. Kullanıcı, tek arayüz üzerinden isteğini iletir. İstek zincire bağlı nesneler tarafından sıra ile ele alınarak karşılanmaya çalışılır. İstek karşılanana dek zincir üzerinde bir nesneden diğerine aktarılır. Zaman içinde zincire yeni nesneler eklenmesi ya da çıkarılması mümkündür. Kullanıcı bu tür değişikliklerden arayüz sayesinde etkilenmez.
- Strateji (İngilizce: strategy pattery)
Aynı arayüz altında, aynı sorunu çözebilecek birçok çözüm yöntemi sınıfını saklayarak kullanıcı nesnelerin hangi yöntemin kullanıldığından haberdar olmaksızın isteklerinin sağlanmasını olanaklı kılar. Kullanıcı nesneler aynı türden nesnelerle çalıştıklarını var sayarken farklı davranış biçimleri ile karşılanırlar.
- Yadigâr (İngilizce: memento pattern)
Yadigâr, uygulama yazılımı içerisinde önemli roller üstlenen nesnelerin durumlarını saklamak ve gerektiğinde nesneleri geçmişteki durumlarına geri döndürmek ya da hatırlatmak için kullanılır.
- Yineleyici (İngilizce: iterator pattern)
Kitlesel bir nesnenin (İngilizce: aggragate object) altında bulunan nesnelere, nesnelerin nasıl temsil edildiklerine ya da gerçeklendiklerine bakılmaksızın, sırasıyla ulaşılmasını sağlar. Bu sayede farklı şekilde temsil edilen nesnelere tek bir arayüz üzerinden ulaşılabilir.
- Yorumlayıcı (İngilizce: interpreter pattern)
Karmaşık uygulamaların gereklerini yerine getirmek için tanımlanan sözde dili işleyecek bir yorumlayıcı kalıbıdır. Sözde dilin gramer kurallarını birer sınıf olarak tanımlayarak kolayca uygulanmasını sağlar. Gramer kuralları sınıflar olarak tanımlandığı için kolayca değiştirilerek geliştirilebilir.
- Ziyaretçi (İngilizce: visitor pattern)
Bileşik bir yapı üzerine yeni işlemler eklenmesine imkân verir. Ziyaretçi nesne bileşik yapı içindeki nesneleri tek tek ziyaret ederek gerekli bilgileri toplayıp işleyerek kullanıcıya sunar.
Oluşturma örüntüleri
Oluşturma örüntüleri, yazılım nesnelerinin (ya da başka bir deyişle sınıf örnekleri - İngilizce: class instances) nasıl oluşturulacağı hakkında öneriler sunar. Ana fikir, iyi bir yazılımın, içinde barındırdığı nesnelerin nasıl oluşturulduğundan bağımsız olarak tasarlanması gerektiğidir. Diğer bir deyişle nesnelerin nereden ve nasıl oluşturulduğu, ait oldukları yazılımın işleyişini etkilememeli; yeni özellikler eklenmesine ve değişikliklere karşı sorun oluşturmamalıdır.
Yazılım sistemleri geliştikçe nesnel bileşimler (İngilizce: object composition), sınıf kalıtımına (İngilizce: class inheritence) göre daha fazla önem kazanır. Bunun nedeni, yazılım sistemleri için basit temel davranış (İngilizce: behavior) şekillerinin tanımlanması üzerine kurulu tasarımların, sabit davranışlara dayalı tasarımlara göre daha esnek olmasındandır. Diğer bir deyişle, nesnelere davranışların bileşim olarak eklenmesi, daha sonra bu davranışların yazılımın gelişimine göre değiştirilmesine olanak sağlar. Bu durumda, geliştirilen yazılım için gereken temel davranış şekillerine dayalı bir tasarım, nesne arayüzleri (İngilizce: interface) değiştirmeden farklı ya da daha karmaşık davranışların kullanılabilmesini mümkün kılar.
Ancak nesnel bileşimler yoluyla temel davranışları sağlayan nesnelerin örneklenmesi, ana ya da kalıtım yoluyla davranış değişikliğine uğratılarak türetilmiş sınıflardan nesne oluşturmak daha zordur. Oluşturma örüntüleri bu zorlukları aşmak amacıyla kullanılabilecek yazılım örüntüleri içerir.
Oluşturma örüntüleri, hem hangi somut sınıfların (İngilizce: concrete class) nesne örneklemesinde kullanıldığını, hem de bu örneklerin nasıl oluşturulup bir araya getirildiğini yazılım sisteminden saklarlar.
- Fabrika yöntemi (İngilizce: factory method)
Nesne oluşturma için kullanılan tek arayüz altında nesnenin nasıl oluşturulacağını kalıtım yoluyla alt sınıflara bırakarak, arayüzle nesne oluşturma işlevlerini birbirinden ayırır.
- Örnek (İngilizce: prototype pattern)
Karmaşık veya pahalı sınıflardan nesne oluştururken yeni nesnelerin baştan oluşturulması yerine mevcutlarından örnekleyerek oluşturulmasını sağlar. Bu sayede yeni nesneler kolayca ve kaynaklar gereksiz yere meşgul edilmeden oluştururlar.
- Soyut fabrika (İngilizce: abstract factory pattern)
Tek arayüz ile bir nesne ailesinin farklı platformlarda oluşturulmasını mümkün kılar. Bu sayede yazılım uygulaması farklı platformlara davranış değişikliğine uğramadan taşınabilir. Soyut fabrika kalıbı, tek arayüz altında hangi somut sınıfların kullanıldığını saklar.
- Yapıcı (İngilizce: builder pattern)
Karmaşık bir nesne grubunun tek arayüz üzerinden gerektiğince parça parça oluşturulmasını sağlar. Kullanıcı nesne grubunu kullandıkça nesne grubu gereken yönde yapılanır. Kullanılmayan parçalar gereksiz yere oluşturularak kaynak harcamaz.
- Yegâne (İngilizce: singleton pattern)
Bir sınıftan sadece bir tane nesne oluşturulacak şekilde kısıtlama sağlar. Söz konusu nesneye uygulamanın her yerinden ulaşılabilir. Nesne ilk kez kullanılana dek oluşturulmayabilir.
Yapısal örüntüler
Yapısal örüntüler sınıfların ve nesnelerin birleştirilerek daha geniş yazılım yapılarının kurulmasına olanak sağlayan öneriler sunar. Sınıf yapı örüntüleri ve nesne yapı örüntüleri olmak üzere ikiye ayrılır.
Sınıf yapı örüntüleri kalıtım kullanarak sınıf arayüzlerini ya da uygulamaları bileştirerek yapıları genişletir. Nesne yapı örüntüleri ise nesnelerin birleştirilerek yeni işlevler kazanma yollarını gösterir.
- Bileşik (İngilizce: composite pattern)
Nesnelerin parça-bütün ilişkisi içinde ağaç yapısı ile bir araya getirilerek birleştirilmesine ve bu bileşiğe tek ara yüzden ulaşılmasına imkân verir. Bileşik yapı yeni nesneler eklenip çıkarılarak zamanla genişleyip daralabilir.
- Cephe (İngilizce: façade pattern)
Karmaşık bir yapının bir arada tutularak tek bir arayüz üzerinden kullanımını mümkün kılar.
- Dekoratör (İngilizce: decorator pattern)
Bir nesneye, nesneyi değiştirmeden yeni sorumluluklar eklenmesini sağlar. Alt sınıflama yapmadan nesnelerin işlevlerinin geliştirilmesini mümkün kılar.
- Köprü (İngilizce: bridge pattern)
Hem arayüzün hem de somut uygulamanın birbirinden ayrılarak düzenlenmesine olanak sağlar. Arayüzün değişimi uygulamayı, uygulamanın değişimi arayüzü etkilemez. Her ikisi bağımsız olarak geliştirilebilir.
- Sinek sıklet (İngilizce: flyweight pattern)
Çok sayıda benzer nesnenin oluşturulması yerine bir örnek nesneden görsel nesneler oluşturarak kalabalık bir imkân verir. Görsel nesnelerin durum değişkenleri nesnenin kendisi tarafından değil kullanıcı tarafından saklanır.
- Uyumlayıcı (İngilizce: adapter pattern)
Farklı kaynaklardan gelen nesne ya da sınıfların arayüzlerini uyumlandırmak amacıyla kullanılır.
- Vekil (İngilizce: proxy pattern)
Karmaşık, pahalı ve oluşturulması güç nesneleri kullanmak için arayüz taklidini olası kılar. Kullanılacak olan nesnenin fiziksel yerini kullanıcıdan saklayacak şekilde yönlendirme yapılmasını sağlar.
Yazılım tasarım örüntülerine eleştiri
Bazı yazarlar, yazılım tasarım örüntülerinin sorunların çözümlerini olumsuz yönde etkilediği yönünde eleştirmektedir. Bazılarına göre de, yazılım örüntüleri programla dilinde veya metodolojisindeki kısıtlamaları ve sorunları göstermektedir ve örüntüyü tespit etmek son aşama olmamalıdır. Yeni programla dillerinde bu örüntüleri gerektirecek durumları engelleyecek çözümler dilin kendisinden sağlanmalıdır. Örneğin bu görüşün taraftarları nesne yönelimli programlamaya ait olarak bilinen kavramların, daha önceki programlama dillerinde tasarım örüntüsü olarak tavsiye edilen kavramlar olduklarını, ama nesne yönelimli dillerin çıkmasıyla bu kavramların dil içinde belirsiz bir şekilde kullanıldığını ve artık bir örüntü olmadıklarını savunmaktadırlar.