C# Composite Design Pattern(Composite Tasarım Deseni)
Merhaba,
Bu içeriğimizde Yapısal Tasarım Kalıplarından(Structural Patterns) olan Composite Tasarım Desenini(Composite Design Pattern) tam teferruatlı inceleyecek ve bol bol örnekler ile zihinlerimize mantıksal yapısını kazımaya çalışacağız. O halde fazla vakit kaybetmeksizin buyrun başlayalım…
Başlarken
Her design pattern makalesinde yaptığımız gibi öncelikle konuya dair bol teorik bilgi verdikten sonra bilgileri pratikselleştirmek için bir örnek üzerinden eş zamanlı anlatım sergileyeceğiz. Ardından Composite pattern’ın stratejik ve mantıksal yapısını daha da özümseyebilmek ve kullanılabileceği durumları hızlıca kavrayabilmek için beş adet örnek senaryo üzerinden pratik gerçekleştiriyor olacağız. Bu senaryoların her biri, çözümü ile birlikte makalemizin altındaki diğer sayfalarda sırasıyla sunuluyor olacaktır. Şimdiden iyi ve verimli okumalar dilerim…
Composite Design Pattern Nedir?
Bazen yazılım tasarımları süreçlerinde nesnelerin ağaç yapıları halinde oluşturulması ve ardından bu yapılarla tek tek nesnelermiş gibi çalışılması gerekebilir. İşte böyle durumlarda Composite pattern tasarımsal açıdan imdadınıza yetişebilir.
Composite pattern, kendi içlerinde birbirlerinden farklı olan bir grup nesnenin sanki tek bir bütün nesneymiş gibi kullanılmasını sağlamaktadır. Böylece farklı nesneleri bir ağaç yapısında birleştirip genel anlamda parça bütün ilişkisini yeniden düzenleyip şekillendirmektedir.
Composite pattern’a teoride şöyle bir örnek verebiliriz.
‘Kutu’ ve ‘Ürün’ olmak üzere iki türlü nesne olduğunu düşünelim. Kutu nesnesi, içerisinde birden fazla ürün barındırabileceği gibi ayriyeten kutu da barındırabilir. Yani bir kutu içerisinde bir başka kutu olabilir. Aynı şekilde kutu içerisindeki kutu da içerisinde ürün barındırabileceği gibi yine farklı bir kutu da barındırabilir. Haliyle bu silsile böyle devam edebilir.
Bu nesnelerin kullanıldığı bir sipariş sistemi oluşturduğumuzu tahayyül edelim ve yandaki görüntüdeki gibi bir sepeti düşünelim. Sepet içerisinde siparişler basit ürünlerden ibaret olabileceği gibi içi ürünlerle dolu kutulardan da ibaret olabilir. İşte böyle bir sipariş durumunda siz olsanız siparişin toplam fiyatını nasıl belirlerdiniz?
Muhtemelen çözüm olarak tüm kutuları tek tek açıp, mevcut tüm ürünleri gözden geçirdikten sonra toplam fiyatı hesaplardınız. Bu gerçek dünyada yapılabilitesi olan yegane yoldur diyebiliriz. Ancak yazılımsal olarak bu hesaplamayı yapabilmek pekte kolay değildir. Nihayetinde iç içe kaç kutu olduğunu bilemediğimiz için recursive bir yaklaşım sergilememiz gerekmektedir.
Composite pattern ise bu tarz ağaç yapısı senaryolarında gerçekleştirilecek bütünsel işlemleri yürütebilmek için her bir composite(kutu) nesnesi üzerinde operasyonu gerçekleştirmektedir. Yukarıdaki teorik örnekte olduğu gibi, toplam fiyatı hesaplayabilmek için her bir kutunun içerdiği ürünler üzerinden toplam fiyatı hesaplayarak öğrenecek ve bunu iç içe olan tüm kutular için gerçekleştirecektir.Bu yaklaşımın en büyük yararı, ağaç yapısını oluşturan alt kırılım sınıflarıyla ilgilenmemize gerek olmamasıdır. Yani bir nesnenin basit bir ürün mü yoksa içinde birden fazla ürün ve kutu barındıran karmaşık bir kutu mu olup olmadığını bilmemize gerek yoktur. Ortak bir arayüz aracılığıyla her iki nesnede aynı muameleyi görecektir. Bu arayüz sayesinde tetiklenen metot üzerinden nesneler bu tetiklenmeyi ağaçtan aşağı ileterek operasyonun yürütülmesini sağlayacaktır.
Gerçek Dünya Analojisi
Biliyorsunuz ki, çoğu ülkenin orduları hiyerarşik olarak yapılandırılmıştır. Bir ordu birbirleriyle ilişkili birkaç bölümden meydana gelmektedir. Misal olarak, bir tümen tugaylardan oluşurken, bir tugay alaylardan oluşmakta, alaylar ise mangalara kadar ayrılan müfrezelerden meydana gelmektedir. Haliyle bu şekilde ilişkilendirilmiş bir yapılanmada hiyerarşinin en üstünden verilen emirler, her seviyedeki tüm askerlere ulaştırılacak şekilde aktarılmaktadır. İşte bu hiyerarşinin düzenlenmesinde Composite pattern rahatlıkla kullanılabilir.
Benzer mantıkla çalıştığınız şirkette veya kurumda ekibin organizasyonel yapısını ve personellerin pozisyonlarını işlevsel ilişkiler üzerinden hiyerarşik olarak gösteren teşkilat şemaları mevcuttur. Bu teşkilat şemaları da tıpkı ordularda olduğu gibi hiyerarşinin en üstünden altına doğru sorumluluk ağlarını göstermektedir. İşlevsel açıdan sorumluluklar, en üstten aşağı doğru her seviyedeki personellere ayrıştırılacak şekilde tasarlanmaktadır. Buradaki mantıkta yazılımsal düzleme Composite pattern ile rahatlıkla aktarılabilir.
Composite Design Pattern’ın Stratejisi
Composite pattern’ın uygulanacağı ağaç yapıları misali tasarımlarda Component, Composite ve Leaf isimlerinde olmak üzere üç farklı sorumlulukta sınıf tasarlanması gerekmektedir.
Bu sınıfların ne olduğunu ve hangi sorumlulukları üstlendiğini açıklamamız gerekirse eğer;
- Component
Ağaç yapısındaki basit ve karmaşık nesneleri ve bu nesnelerin ortak alanlarını açıklayan abstract sınıftır. - Composite
Ağaç yapısındaki karmaşık nesnelere karşılık gelen sınıftır. Daha teknik bir izahatte bulunmamız gerekirse eğer Component‘lerin bir araya geldiği ve ağaç yapısındaki alt kırılımları oluşturan kompleks nesneleri temsil etmektedir. - Leaf
Ağaç yapısındaki en temel unsuru olan ve alt kırılım barındırmayan tek bir Component nesnesidir. Yani basit nesneyi ifade eder.

Composite Pattern stratejisinin katılımcıları yukarıda görüldüğü gibidir… Burada dikkat edilmesi gereken nokta; basit öğeler Leaf, karmaşık öğeler ise Composite olarak nitelendirilmektedir…
Composite pattern’da birden çoğa hiyerarşik yapılanma söz konusudur.
Teknik Olarak Composite Design Pattern
Composite pattern’ı teknik olarak inceleyebilmek için yukarıdaki satırlarda değindiğimiz gerçek dünya analojisindeki asker senaryosundan yola çıkalım ve pratiksel açıdan ilgili senaryonun örneğini gerçekleştirerek seyredelim.
SENARYO |
---|
Emir komuta sistemine sahip ordu modelini yazılımsal olarak inşa edelim ve üst rütbelerden gelen emirleri tüm seviyelerdeki askerlere iletelim. |
ÇÖZÜM |
---|
|
Client açısından tekil nesneler ile nesne grupları arasındaki farklılıkları görmeksizin işlem yapmak için Composite pattern kullanılabilir.
Uygulanabilirlik
Yukarıda görüldüğü üzere Composite pattern, Leaf ve Composite yapılarından oluşan ve bu yapılar arasında stratejik bir ayrım sağlayan tasarım desenidir. İhtiyaç olarak ağaç yapısı(bir başka deyişle hiyerarşik) operasyonlarında özyinelemeli(recursive) nesne yapısı oluşturulmasına olanak sağlamaktadır. Bu recursive operasyon esnasında client, hem Leaf hem de Composite yapıları ekstra çabalara girişmeksizin aynı şekilde(fark yaratmaksızın) işlemektedir.
Lehte ve Aleyhte Durumlar
✓ | ꭕ |
---|---|
Karmaşık ağaç yapılarıyla rahatlıkla çalışılabilir. | İşlevselliği çok farklı olan sınıflar için ortak bir arayüz sağlamak zor olabilir. Belirli senaryolarda Component arayüzünü aşırı genelleştirmek gerekebilir. Haliyle bu durumda ilgili tasarımın anlaşılmasını zorlaştırabilir. |
Nesne ağacıyla çalışan nesneleri mevcut kodu bozmadan uygulamaya ekleyebildiğimizden dolayı Open Closed prensibiyle uyumludur. | Composite pattern, yukarıdaki senaryonun 3. adımında bahsedildiği üzere Interface Segregation prensibine aykırı olabilir. |
Daha az bellek yönetimi gerektirmektedir. | |
Esnektir. |
İlkel(Leaf) ve karmaşık(Composite) nesnelerin işlenmesi farklı şekilde ele alınır. Haliyle her nesneyi işlemeden önce türünü sorgulama zahmetine katlanmaksızın Composite pattern ile hızlı çözüm getirebilirsiniz.
Diğer Kalıplarla İlişkisi
- Karmaşık Composite ağaçlar oluştururken Builder Design Pattern kullanılabilir.
- Chain of Responsibility, genellikle Composite pattern ile birlikte kullanılır. Bu durumda bir yaprak(Leaf) herhangi bir istek aldığında o isteği tüm ana bileşenlerin zincirinden geçirerek nesne ağacının köküne kadar iletebilir.
- Composite ağacını tüm alt kırılımlarıyla birlikte tetikleyebilmek için Iterator Design Pattern kullanılabilir.
- Composite ağacının tamamının üzerinde bütünsel işlem yapabilmek için Visitor Design Pattern kullanılabilir. Bununla ilgili, Visitor pattern için referans edilen ilgili makalemde Kritik başlığı altındaki yorumu okuyabilir ve örneği inceleyebilirsiniz.
- Yoğun Composite pattern’ı kullanan tasarımlarda Prototype Design Pattern kullanılarak karmaşık yapıları sıfırdan oluşturma maliyeti ortadan kaldırılabilir.
Genel Görüşler
Composite pattern’ın tüm amacı birbirleriyle ilişkili karmaşık(composite) yapıların tıpkı bir yaprak gibi atomik olarak işlenebilmesidir. Nihayetinde bu kalıbın merkezinde, bir client’ın içinde bir çok nesne olduğunu bilmesine gerek kalmaksızın ilkel ve karmaşık nesneler(ağaç yapısı) üzerinde işlem yapabilme yeteği yatmaktadır.
Composite pattern ile heterojen olan ilkel(Leaf) ve karmaşık(Composite) nesne koleksiyonunu atomik olarak ele alabilmek için gerekli fonksiyonların Component arayüzünde tanımlanması yeterlidir. Ancak bu tanımlama, önceki satırlarda da değindiğimiz gibi(özellikle pratik örneğin 3. adımında) Leaf nesnelerinde de implemantasyona neden olacağından dolayı olası güvensizliğe mâl olabilir. Çünkü client’lar Leaf nesneler üzerinden Composite nesnelere özel olan fonksiyonları kullanmak gibi anlamsız eylemler yapabilir. Halbuki Component‘te tanımlı olan composite fonksiyonları Leaf nesneleri için bir anlam ifade etmeyecektir. Haliyle bu durum daha önceden de bahsedildiği gibi Arayüz Ayrım Prensibine aykırı olabilir. Bunu engellemek için Component‘i ikiye ayırıp composite fonksiyonlarını farklı bir arayüze alabilir ve Composite nesneleri o arayüzden türetebilirsiniz.
Evet, böylece bir design pattern makalesinin daha sonuna gelmiş olduk. Sonraki sayfalarda konuya dair farklı senaryolarda bol pratik örnekler sergilemekteyim. Kesinlikle göz atmanızı ve mümkünse teoride bırakmayıp pratik ile desteklemenizi tavsiye ederim.
İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…