Structural — Yapısal Desenler

Decorator

Dekoratör (Süsleyici) Deseni

Amaç: Bir nesneye, sınıfını değiştirmeden ve kalıtım kullanmadan, çalışma zamanında katman katman yeni davranışlar eklemek.

1

Basit Anlatım

Teknik terim yok — günlük hayattan bir benzetme

Bir kahve dükkânındasınız. Sade bir filtre kahve sipariş ediyorsunuz: 40 TL. "İçine süt ekleyin" diyorsunuz: +10 TL. "Bir de karamel şurubu": +15 TL. "Üstüne krema": +12 TL.

Kahve hâlâ kahve; ama her eklemeyle üstüne bir katman giydirildi. Dükkânın menüsünde "sütlü-karamelli-kremalı kahve" diye ayrı bir ürün yok. Sadece bir temel ürün ve istediğiniz gibi birleştirebileceğiniz eklemeler var.

Kış giyimi

Hava soğuyunca tişörtün üstüne kazak, onun üstüne mont, yağmur yağarsa en üste yağmurluk giyersiniz. Her katman size yeni bir özellik kazandırır (sıcaklık, su geçirmezlik) ve istediğiniz zaman çıkarabilirsiniz. Siz değişmediniz, sadece giydikleriniz değişti.

Decorator şunu der: "Nesneyi değiştirme; onu yeni özellik kazandıran katmanlarla sar."
2

Teknik Anlamı

Bir yazılımcının bakış açısıyla

Decorator, sarmaladığı nesneyle aynı arayüzü uygulayan bir sarmalayıcıdır (wrapper). İsteği içerideki nesneye iletir ve öncesinde/sonrasında kendi davranışını ekler. Dekoratörler iç içe geçirilerek davranışlar birleştirilir.

Problem: Kalıtım patlaması

Bir veri kaynağına sıkıştırma, şifreleme ve loglama eklemek isteyelim. Kalıtımla CompressedEncryptedLoggedStream gibi her kombinasyon için ayrı sınıf gerekir. Üstelik bu kombinasyonlar derleme zamanında sabitlenir.

Katılımcılar

.NET'ten tanıdık örnekler

Avantajlar

Dezavantajlar

3

C# ile Uygulama

Adım adım, çalışan kod örneği

Senaryo: Bir veri kaynağına yazılan metne isteğe bağlı olarak sıkıştırma, şifreleme ve loglama eklemek. (Örnek basit tutulmak için gerçek algoritmalar yerine görünür dönüşümler kullanıyor.)

Adım 1 Component ve temel uygulama

public interface IDataSource
{
    void Write(string data);
    string Read();
}

public class MemoryDataSource : IDataSource
{
    private string _stored = "";
    public void Write(string data) => _stored = data;
    public string Read() => _stored;
}

Adım 2 Temel dekoratör

Varsayılan olarak her şeyi içerideki nesneye iletir. Somut dekoratörler yalnızca değiştirmek istedikleri kısmı override eder.

public abstract class DataSourceDecorator : IDataSource
{
    protected readonly IDataSource Inner;

    protected DataSourceDecorator(IDataSource inner) => Inner = inner;

    public virtual void Write(string data) => Inner.Write(data);
    public virtual string Read() => Inner.Read();
}

Adım 3 Somut dekoratörler

public class EncryptionDecorator : DataSourceDecorator
{
    public EncryptionDecorator(IDataSource inner) : base(inner) { }

    // Basit gösterim: metni ters çevirip Base64'e dönüştürür.
    public override void Write(string data) =>
        base.Write(Convert.ToBase64String(
            System.Text.Encoding.UTF8.GetBytes(new string(data.Reverse().ToArray()))));

    public override string Read() =>
        new string(System.Text.Encoding.UTF8.GetString(
            Convert.FromBase64String(base.Read())).Reverse().ToArray());
}

public class CompressionDecorator : DataSourceDecorator
{
    public CompressionDecorator(IDataSource inner) : base(inner) { }

    // Basit gösterim: art arda gelen boşlukları tek boşluğa indirir.
    public override void Write(string data) =>
        base.Write(System.Text.RegularExpressions.Regex.Replace(data, " +", " "));
}

public class LoggingDecorator : DataSourceDecorator
{
    public LoggingDecorator(IDataSource inner) : base(inner) { }

    public override void Write(string data)
    {
        Console.WriteLine($"  [LOG] Yazılıyor: \"{data}\"");
        base.Write(data);
    }

    public override string Read()
    {
        var result = base.Read();
        Console.WriteLine($"  [LOG] Okundu: \"{result}\"");
        return result;
    }
}

Adım 4 Kullanım

Tüm parçaları bir araya getiren istemci (client) kodu:

var memory = new MemoryDataSource();

// Katmanlar: Log -> Sıkıştırma -> Şifreleme -> Bellek
IDataSource source =
    new LoggingDecorator(
        new CompressionDecorator(
            new EncryptionDecorator(memory)));

source.Write("Gizli     müşteri     verisi");
Console.WriteLine($"Bellekte duran ham veri : {memory.Read()}");
Console.WriteLine($"Uygulamanın okuduğu veri: {source.Read()}");

Console.WriteLine("\nSadece loglama istenirse:");
IDataSource simple = new LoggingDecorator(new MemoryDataSource());
simple.Write("Herkese açık veri");

Konsol çıktısı

  [LOG] Yazılıyor: "Gizli     müşteri     verisi"
Bellekte duran ham veri : aXNpcmV2IGlyZXTFn8O8bSBpbHppRw==
  [LOG] Okundu: "Gizli müşteri verisi"
Uygulamanın okuduğu veri: Gizli müşteri verisi

Sadece loglama istenirse:
  [LOG] Yazılıyor: "Herkese açık veri"

Kodda dikkat edilmesi gerekenler

Özetle: Decorator, nesneyi aynı arayüzü uygulayan sarmalayıcılarla katman katman zenginleştirir; kalıtım patlamasını önler ve davranışları esnekçe birleştirir.
← Ana sayfaya dön