Decorator Design Pattern


🎯 Decorator Design Pattern – بالبلدي كده

الـ Decorator Pattern هو واحد من الـ Structural Design Patterns
فكرته ببساطة إنه بيسمحلك تزود سلوك (Behavior) على Object معيّن في وقت التشغيل (Runtime)
من غير ما:

  • تعدّل في الكلاس الأصلي
  • ولا تعمل inheritance على الفاضي

وده بيحصل عن طريق إنك تلفّ الـ object جوه object تاني (الـ Decorator) يزوّد له شغل إضافي.

يعني بدل ما تغيّر العربية نفسها، بتزوّد لها إكسسوارات 😄


⏰ نستخدم Decorator إمتى؟

نستخدمه لما:

  • تكون محتاج تزود شغل على object من غير ما تغيّر الكود الأصلي
  • الوراثة (Inheritance) تعملك انفجار كلاسّات وصعوبة صيانة
  • تكون محتاج تركيبات مختلفة من السلوك تتضاف وتشيلها وقت التشغيل

🧩 مكوّنات Decorator Pattern

1️⃣ Component

  • Interface أو Abstract Class
  • بيحدد الـ contract المشترك

2️⃣ Concrete Component

  • التنفيذ الأصلي
  • ده الـ object الأساسي اللي عايز تزود عليه شغل

3️⃣ Decorator

  • كلاس abstract
  • بيلفّ الـ Component
  • ممكن يغيّر أو يزوّد سلوكه

4️⃣ Concrete Decorator

  • التنفيذ الفعلي
  • بيضيف وظيفة جديدة، وفي نفس الوقت بينادي على الـ object اللي جواه

☕ مثال القهوة (من غير Decorator)

افترض عندك كلاس Coffee
وعايز تضيف:

  • لبن
  • سكر

الطريقة الساذجة: Subclasses

public class Coffee
{
    public virtual string GetDescription() => "Coffee";
    public virtual double GetCost() => 5.0;
}

public class CoffeeWithMilk : Coffee
{
    public override string GetDescription() => base.GetDescription() + " + Milk";
    public override double GetCost() => base.GetCost() + 1.5;
}

public class CoffeeWithSugar : Coffee
{
    public override string GetDescription() => base.GetDescription() + " + Sugar";
    public override double GetCost() => base.GetCost() + 0.5;
}

public class CoffeeWithMilkAndSugar : Coffee
{
    public override string GetDescription() => base.GetDescription() + " + Milk + Sugar";
    public override double GetCost() => base.GetCost() + 2.0;
}

❌ مشاكل الطريقة دي

  • Class Explosion
    كل إضافة جديدة = كلاس جديد
  • صعبة التوسعة
    لو ضفت كراميل مثلًا؟ هتدخل في دوّامة كلاسّات

🔧 الحل الصح: Decorator Pattern

Step 1: نعمل Component Interface

public interface ICoffee
{
    string GetDescription();
    double GetCost();
}

Step 2: Concrete Component (القهوة السادة)

public class SimpleCoffee : ICoffee
{
public string GetDescription() => "Coffee";
public double GetCost() => 5.0;
}

Step 3: Abstract Decorator

public abstract class CoffeeDecorator : ICoffee
{
    protected readonly ICoffee _coffee;

    public CoffeeDecorator(ICoffee coffee)
    {
        _coffee = coffee;
    }

    public virtual string GetDescription() => _coffee.GetDescription();
    public virtual double GetCost() => _coffee.GetCost();
}

Step 4: Concrete Decorators (الإضافات)

🥛 Milk

public class MilkDecorator : CoffeeDecorator
{
    public MilkDecorator(ICoffee coffee) : base(coffee) { }

    public override string GetDescription() => base.GetDescription() + " + Milk";
    public override double GetCost() => base.GetCost() + 1.5;
}

🍬 Sugar

public class SugarDecorator : CoffeeDecorator
{
    public SugarDecorator(ICoffee coffee) : base(coffee) { }

    public override string GetDescription() => base.GetDescription() + " + Sugar";
    public override double GetCost() => base.GetCost() + 0.5;
}

Step 5: الاستخدام (Runtime)

ICoffee coffee = new SimpleCoffee();
Console.WriteLine($"{coffee.GetDescription()} - ${coffee.GetCost()}");

// Add Milk
coffee = new MilkDecorator(coffee);
Console.WriteLine($"{coffee.GetDescription()} - ${coffee.GetCost()}");

// Add Sugar
coffee = new SugarDecorator(coffee);
Console.WriteLine($"{coffee.GetDescription()} - ${coffee.GetCost()}");

🖨️ Output

Coffee - $5.0
Coffee + Milk - $6.5
Coffee + Milk + Sugar - $7.0

✅ مميزات Decorator Pattern

✔ مرن جدًا – تزود وتشيل سلوك وقت ما تحب
✔ ملتزم بمبدأ Open/Closed
✔ مفيش Class Explosion
✔ سهل التركيب والتوسعة


❌ عيوبه

✖ عدد كلاسّات أكتر
✖ ترتيب الـ decorators مهم (الترتيب ممكن يفرق في النتيجة)


🌍 استخداماته في الواقع

  • Logging
    تزود Logging على Service من غير ما تمس كوده
  • Caching
    تلف Repository بـ Caching Layer
  • Authentication / Authorization
    Middleware قبل التنفيذ
  • UI Components
    تزود Styles أو Behaviors زي Tooltips أو Scrollbars

🧠 الخلاصة

  • Decorator Pattern بيديك طريقة نظيفة ومرنة تزود بيها شغل على object
  • ممتاز للحاجات اللي بتتغيّر أو بتتركّب
  • بيحل مشكلة الوراثة الزايدة والكلاسّات اللي ملهاش آخر

Comments