Decorator Design Pattern (Tasarım Deseni) – C#

Bir nesnenin davranışını genişletmek için inheritance veya composition kavramlarını kullanırız, ancak bu derleme zamanında yapılır ve sınıfın tüm örneklerine uygulanabilir. Bizim bunu istemediğimiz durumlarda Decorator Design Pattern devreye girer. Decorator Design Pattern, sınıfın yapısında değişikliğe gidilmeksizin belirli bir nesneye veya bazı nesnelere yeni ek fonksiyon ve özelliklerin dinamik olarak eklenmesi amacıyla kullanılmaktadır. Burada ki önemli ayrıntı yeni özelliğin sınıfa değil de belir bir nesneye kazandırılıyor olmasıdır. Ve aynı sınıftan üretilen diğer nesneler bu dekorasyondan etkilenmezler.

UML Class Diyagramı

Decorator UML Diyagram

Kullanım Sıklığı: orta

Decorator Prensipleri

  • Component: Uygulanacak metotları tanımlayan interface veya abstract sınıf.
  • ConcreteComponent: Bileşen interface’in temel uygulaması.
  • Decorator: bileşen interface’ini uygular ve bileşen interface ile bir HAS-A ilişkisine sahiptir. Dekore edeceği nesnenin referansını içerir. Bileşen değişkeni, alt dekoratör sınıfları tarafından erişilebilir olmalıdır, bu nedenle bu değişkeni protected hale getireceğiz.
  • ConcreteDecorator: Görevi temel dekoratör işlevselliğini genişletmek ve bileşen davranışını buna göre değiştirmek.

C# Decorator Design Pattern Uygulama

Bu senaryomuzda bir Sayfa Görünümü görevi gören Window sınıfımız ve ondan türeyen LoginWindow ve ReportWindow sınıflarımız var. Bu sınıflardan türeyen sayfa nesnelerimize Decorator pattern kullanarak tema özelliği kazandıracağız.

Component Class

    //Component - Sayfa özelliklerini taşıyan soyut bir sınıf inşa ediyoruz. 
    public abstract class Window
    {
        protected string title;
        public string Title
        {
            get { return title; }
            set { title = value; }
        }
        public Window()
        {
            title = "";
        }
        public Window(string title)
        {
            this.title = title;
        }
        //Türetilen sınıflarda uygulamak üzere render metodu tanımlıyoruz.
        public abstract void Render();
    }

ConcreteComponent Class

//ConcreteComponent
    public class ReportWindow : Window
    {
        public ReportWindow()
        {

        }
        public ReportWindow(string title) : base(title)
        {

        }
        //Override base window class
        public override void Render()
        {
            Console.WriteLine("{0} Başlıklı Rapor ekranı render edildi", title);
        }
    }

    //ConcreteComponent
    public class LoginWindow : Window
    {
        public LoginWindow()
        {

        }
        public LoginWindow(string title) : base(title)
        {

        }
        //Override base window class
        public override void Render()
        {
            Console.WriteLine("{0} Başlıklı Login ekranı render edildi", title);
        }
    }

Decorator Class

//Decarator
public abstract class WindowDecorator : Window
{
    private Window targetWindow;
    public Window TargetWindow
    {
        get { return targetWindow; }
        set { targetWindow = value; }
    }
    public WindowDecorator(Window targetWindow, string title)
    {
        this.targetWindow = targetWindow;
        this.targetWindow.Title = title;
    }
}

ConcreteDecorator Class

//ConcreteDecorator
public class ThemeDecorator : WindowDecorator
{
    public ThemeDecorator(Window targetWindow, string title) : base(targetWindow, title)
    {
    }
    //Override base window class (WindowDecorator, Window class'ından türediği için burada window class'ın metodu override edilebilir.)
    public override void Render()
    {
        TargetWindow.Render();
    }
    public void SetTheme(string name)
    {
        Console.WriteLine("{0} başlıklı pencere {1} teması uygulandı", TargetWindow.Title, name);
        Render();
    }
}

Program.cs – Main Method

//Pencere sayfaları oluşturuluyor.
Window w1 = new LoginWindow("Sisteme giriş");
Window w2 = new ReportWindow("Stok Raporu Ekranı");
Window w3 = new ReportWindow("Satış Raporu Ekranı");

//Oluşturulan pencerelere decorator ile theme yüklemesi yapılıyor.
ThemeDecorator decorator1 = new ThemeDecorator(w1, "Sisteme Giriş");
ThemeDecorator decorator2 = new ThemeDecorator(w2, "Stok Raporu Ekranı");
ThemeDecorator decorator3 = new ThemeDecorator(w3, "Satış Raporu Ekranı");

decorator1.SetTheme("Ayder Teması");
decorator2.SetTheme("Ürgüp Teması");
decorator3.SetTheme("Pamukkale Teması");

Sonuç

Sisteme Giriş başlıklı pencere Ayder Teması teması uygulandı
Sisteme Giriş Başlıklı Login ekranı render edildi
Stok Raporu Ekranı başlıklı pencere Ürgüp Teması teması uygulandı
Stok Raporu Ekranı Başlıklı Rapor ekranı render edildi
Satış Raporu Ekranı başlıklı pencere Pamukkale Teması teması uygulandı
Satış Raporu Ekranı Başlıklı Rapor ekranı render edildi

Decorator Design Önemli Noktalar

  • Decorator tasarım deseni, çalışma zamanı değiştirme yetenekleri sağlamada yardımcı olur ve bu nedenle daha esnektir. Seçenek sayısı fazla olduğunda bakımı ve genişletilmesi kolaydır.
  • Decorator tasarım deseninin dezavantajı, birçok benzer türde nesne kullanmasıdır.
  • Dekoratör deseni, FileReader, BufferedReader vb. IO sınıflarında çok kullanılır.