Decorator Design Pattern Nedir?

Fatih İzgi
Kodcular
Published in
4 min readAug 9, 2022

Design Patterns eğitim serisindeki ilk yazımızda, tasarım desenlerinin “Yazılımcıların sıklıkla karşılaştığı problemlere ve yazılımların doğasında bulunan genel ihtiyaçlara getirilen çözümler” olduğunu söylemiştik. Sık karşılaşılan problemlerden bir tanesi ise; aynı türde fakat yapıları farklı nesnelerin üretimini en az karmaşıklık ile gerçekleştirme ihtiyacıdır. Bu yazımızda, bu problemi çözmek için kullanabileceğimiz Decorator Design Pattern yapısını inceleyeceğiz.

Konuya başlamadan önce problemin ne olduğunu biraz analiz edelim;

Waffle yemek için bir mekana oturdunuz ve menüye göz atmaya başladınız. Seçeneklerden birini beğendiniz fakat menüde bulunmadığı için tatlınıza ekstradan muz koymalarını rica ettiniz. İşletme sahibinin ekstradan muz için bir fiyat belirlememiş olduğunu varsayalım. Bu durumda var olan waffle üzerine muz ekleyerek yeni bir fiyatla menüye dahil etmesi gerekecektir. İsteklerin ekstradan çilek, hem çilek hem muz, kivi, hem kivi hem çilek gibi çeşitlenmesi üzerine menü, yüzlerce farklı çeşit waffle seçenekleri ile dolu olacaktır ki bu da içinden çıkılmayacak bir problemi beraberinde getirir. Bu durum yazılım dünyasında da geçerlidir. Aynı türde fakat farklı kombinasyonda özelliklere sahip nesnelerin olması gerekebilir ve her nesne için ayrı bir sınıf yaratmak projeyi içinden çıkılamayacak bir karmaşıklığa sürükleyecektir.

Bir yarış oyunu için yazılım geliştirdiğimizi varsayalım. Kullanıcıya BMW, Audi ve Mercedes marka arabalardan seçme şansı verelim. Ayrıca kullanıcılar, bu araçların farklı paketlerini satın alabiliyor olsunlar. Oyundaki her araç için Sunroof, Yağmur sensörü, Hız sabitleyici ve Yol bilgisayarı özellikleri ile farklı paketler bulunmaktadır. Default bir araba ve ekstradan bu özellikleri içeren alt sınıflar oluşturmak oldukça karmaşık olacaktır. Örneğin, Audi marka, yalnızca sunroof bulunan bir araç; Audi marka, sunroof ve yağmur sensörü bulunan bir araç; Audi marka, yalnızca yağmur sensörü bulunan bir araç… Oluşturulabilecek kombinasyonların sayısı yeni marka araçların eklenmesi veya yeni özelliklerin paketlere dahil edilmesi ile sürekli olarak artacaktır. Dolayısıyla, her bir paket için yeni bir sınıf tanımlamak kesinlikle mantıklı bir çözüm olmayacaktır.

Decorator Design Pattern, nesnelerin farklı kombinasyonlar ile farklı özelliklere sahip olabilmesini (karmaşıklıktan uzak bir şekilde) sağlamak amacı ile kullanılır. Bunu yapmak için farklı sınıfların oluşturulmasındansa her bir özellik için bir sınıf tanımlayarak, var olan nesnenin üzerine bu sınıf özelliklerini ekleyerek yeni nesne oluşturulmasını sağlar. Yapısal(Structural) tasarım desenlerinden biridir ve kullanılması ile potansiyel yazılım karmaşasının önüne geçilmesi, hata riskinin azaltılması ve istemcinin isteklerinin sınırlandırılmaması gibi faydalar sağlar.

Desenin uygulaması için kodlamaya soyut sınıflar ile başlayalım :

Görüldüğü gibi, ICar isimli bir Interface ve bu arayüzü implement eden BasicCar isimli bir sınıf oluşturduk. BasicCar sınıfı nesneleri, herhangi bir ekstra özellik bulundurmayan default araç sınıfımızı temsil ediyor. Bu aracın ekstra paket özelliklerini tutmak amacıyla da (ileride oluşturulacak olan)Package tipinde elemanları tutan bir liste bulunmakta. BasicCar sınıfındaki bu liste, henüz yeni yaratılmış ve herhangi bir eleman eklenmemiş bir listedir. Artık Package sınıfını ve ekstra özellikleri oluşturabiliriz :

Görüldüğü gibi, Package adında bir soyut sınıf tanımladık. Bu sınıf da nihayetinde bir araç paketini temsil ettiğinden dolayı ICar Interface’ini implement etmektedir. Bu sınıftan türeyen Sunroof, RainSensor, CruiseControl ve TripComputer sınıfları ise aslında bu özellikleri bulunduran araçları temsil etmektedir. Her biri, bir araba nesnesi almakta ve aldığı araba nesnesine yeni bir parça eklemektedir. Ayrıca, Package sınıfında bulunan liste, her alt sınıfta yedeklenmekte ve yeni özelliğe göre güncellenmektedir. Böylece aracın hangi ekstra parçalara sahip olduğu bilgisi takip edilebilir. Temel yapı tamamlandıktan sonra nesne üretim aşamasına geçilebilir. Kod karmaşasını engellemek adına nesne üretimini tek bir sınıf üzerinden gerçekleştirebiliriz :

Not : Bu sınıf, aksi bir durum söz konusu değilse Singleton olarak da tasarlanabilir.

Görüldüğü üzere, CarProvider sınıfında her bir marka aracın üretimi için ayrı bir metot bulunmaktadır. Ayrıca, ekstra özellikleri default araca ekleyerek yeni bir araç nesnesi oluşturmakla yükümlü olan addExtras() metodu da bu sınıf içerisindedir. Bu metot, ilgili desenin kilit noktası olarak düşünülebilir. Bu metot ve kurulan yapı sayesinde her bir kombinasyona ait sınıf oluşturmadan, istenilen kombinasyonlara sahip araba nesnesi üretmek mümkün hale gelmiştir :

Sonuç olarak, her bir ekstra özellik için toplamda n! sayıda araba sınıfı oluşturmaktansa default bir araba üzerinden yeni özelliklere sahip yeni araba nesneleri oluşturulmuştur. Ekstra özellik sayısının artması ile n! sınıf sayısının binlere belki yüz binlere çıkması engellenmiş, potansiyel bir karmaşanın önüne geçilmiştir. Elbette böylece, hata yapma riski de minimuma indirgenmiştir.

TÜM YAPI

Decorator Design Pattern konusunun ayrıntılarını ve inceliklerini öğrendiğimize göre tüm yapıyı incelemeye başlayabiliriz :

Output :

Marka : BMW

Bulunan Özellikler;

-Sunroof

-Hız Sabitleyici

-Yol Bilgisayarı

Fiyat : 731000.0

Marka : Audi

Bulunan Özellikler;

Fiyat : 720000.0

Marka : Mercedes

Bulunan Özellikler;

-Sunroof

-Yağmur Sensörü

-Hız Sabitleyici

-Yol Bilgisayarı

Fiyat : 754000.0

Yararlandığım Kaynaklar :

1- GeeksForGeeks

2- Refactoring Guru

3- TutorialsPoint

--

--