Decorator Pattern ile Davranış Genişletme konusunu anlatan renkli 3D teknik illüstrasyon

Giriş

Bir sınıfın davranışını dinamik olarak genişletmek istiyorsanız, alt sınıflarla kalıtımı çoğaltmak yerine Decorator Pattern kullanarak mevcut nesneye ek sorumluluklar ekleyebilirsiniz.
Örneğin; bir loglama servisine Caching, Retry veya Validation gibi ek fonksiyonlar eklemek için ideal bir çözümdür.


1. Decorator Pattern Temel Kavramları

  • Component: Temel arayüz veya soyut sınıf.

  • ConcreteComponent: Asıl işlevi yerine getiren sınıf.

  • Decorator: Component’i implement eden ve bir Component referansı tutan sarmalayıcı; ortak soyut base sınıf zorunlu değildir.

  • ConcreteDecorator: Ek davranışları uygulayan sınıflar.


2. Decorator Pattern kod örneği

A. Component Arayüzü

public interface IMessage
{
    void Send(string content);
}

B. ConcreteComponent

public class EmailMessage : IMessage
{
    public void Send(string content)
    {
        Console.WriteLine($"Email gönderildi: {content}");
    }
}

C. Base Decorator

public abstract class MessageDecorator : IMessage
{
    protected readonly IMessage _inner;

    protected MessageDecorator(IMessage inner) =>
        _inner =
            inner ?? throw new ArgumentNullException(nameof(inner));

    public virtual void Send(string content)
    {
        _inner.Send(content);
    }
}

D. ConcreteDecorator’lar

using System.Text;

public class LoggingDecorator : MessageDecorator
{
    public LoggingDecorator(IMessage inner)
        : base(inner) { }

    public override void Send(string content)
    {
        ArgumentNullException.ThrowIfNull(content);
        Console.WriteLine(
            $"[Log] Mesaj gönderiliyor; uzunluk: {content.Length}"
        );
        base.Send(content);
    }
}

public class EncodingDecorator : MessageDecorator
{
    public EncodingDecorator(IMessage inner)
        : base(inner) { }

    public override void Send(string content)
    {
        var encoded = Convert.ToBase64String(
            Encoding.UTF8.GetBytes(content)
        );
        Console.WriteLine("[Encode] Base64 dönüşümü");
        base.Send(encoded);
    }
}

E. Kullanım

IMessage email = new EmailMessage();
IMessage loggedEmail = new LoggingDecorator(email);
IMessage encodedLoggedEmail = new EncodingDecorator(loggedEmail);
encodedLoggedEmail.Send("Merhaba Dünya");
// Output:
// [Encode] Base64 dönüşümü
// [Log] Mesaj gönderiliyor; uzunluk: 20
// Email gönderildi: TWVyaGFiYSBEw7xueWE=

3. Decorator Pattern ve katman sınırı

Katman Rol
Application IMessage contract’ı ve uygulama davranışları
Infrastructure Gerçek e-posta/encoding/logging adaptörleri; bağımlılıklarına göre yerleştirme
API/UI Decorator zincirini oluşturan yapılandırma kodu

4. Avantajlar & Dezavantajlar

Avantajlar

  • Esnek Genişletme: İstenilen sayıda decorator ekleyebilirsiniz.

  • Ayrı Sorumluluk: Logging, Encoding gibi davranışlar ayrı sınıflarda.

  • Dinamik Zincir: Çalışma zamanında decorator’ları değiştirebilirsiniz.

Dezavantajlar

  • Çoklu Katman: Derin decorator zinciri kodu izlemeyi zorlaştırabilir.

  • Konfigürasyon Maliyeti: Client’ın dekoratörleri sıralı şekilde oluşturması gerekir.


İleri Okuma ve Kaynaklar


5. Sonuç

Decorator Pattern ile:

  • Mevcut nesneleri bozmadan yeni davranışlar ekleyin.

  • Katmanlı mimaride sorumlulukları net ayırın.

  • Dinamik ve test edilebilir bir genişletme altyapısı oluşturun.

Base64 bir encoding işlemidir; anahtar, gizlilik veya bütünlük koruması sağlamaz. Örnek bu yüzden EncodingDecorator adını kullanır. Convert.ToBase64String belgesi byte’ların string temsiline dönüşümünü açıklar. EmailMessage yalnız console demo’sudur, e-posta göndermez; System.Text using’i sınıf dosyasının başına gelir.

Sıra davranışı değiştirir: dıştaki EncodingDecorator önce dönüştürür, LoggingDecorator encoded metnin uzunluğunu görür. Payload loglamayı varsayılan yapmayın. Retry ekleyeceğiniz mesaj gönderiminde idempotency ve kısmi başarıyı ayrıca tasarlayın; wrapper sayısı güvenilirliği otomatik artırmaz. Karşılaştırma için Chain of Responsibility isteği devretme ve short-circuit akışını açıklar.

Aynı interface’i uygulamak aynı davranış sözleşmesini garanti etmez. Alıcı düz metin bekliyorsa encoding wrapper’ı şeffaf değildir; format üzerinde anlaşma gerekir. Ayrıca inner çağrı exception üretirse başarı log’u yazmayın. Tablo olası bir yerleşimdir: somut e-posta transport’u ve dış servis bağımlılıkları Infrastructure’a aittir, her decorator için tek zorunlu katman yoktur.

By tanju.bozok

Senior .NET Engineer | Backend architecture, distributed systems & real-time communication