تخطَّ إلى المحتوى

🧩 شرح أنماط التصميم (Design Patterns)

نمطا Adapter و Facade

الدرس 9 من 28· ⏱ 2 دقائق قراءة· 🗓 آخر تحديث: ١٦ أكتوبر ٢٠٢٦

مقدمة

بعد أن تعلمنا الأنماط الأساسية، ننتقل إلى نمطين هيكليين مهمين: Adapter و Facade. كلاهما يهدف إلى تبسيط التفاعل بين الكائنات لكن بطرق مختلفة.

نمط Adapter (المُكيّف)

يحوّل واجهة كلاس إلى واجهة أخرى يتوقعها العميل. يسمح للكلاسات غير المتوافقة بالعمل معًا.

// واجهة قديمة
class OldPrinter {
  printText(text) {
    console.log(`Old: ${text}`);
  }
}

// واجهة جديدة يتوقعها العميل
class NewPrinter {
  print(data) {
    // واجهة مختلفة
  }
}

// Adapter
class PrinterAdapter {
  constructor(oldPrinter) {
    this.oldPrinter = oldPrinter;
  }

  print(data) {
    this.oldPrinter.printText(data);
  }
}

const old = new OldPrinter();
const adapter = new PrinterAdapter(old);
adapter.print("Hello"); // يعمل مع الواجهة الجديدة

⚠️ الـ Adapter لا يضيف سلوكًا جديدًا — هو فقط يكيِّف الواجهة الموجودة.

أنواع الـ Adapter

  • Object Adapter: يستخدم التركيب (Composition) — الأفضل.
  • Class Adapter: يستخدم الوراثة (Inheritance) — أقل مرونة.

أشهر استخدام: تغليف مكتبة خارجية

نظامك يتوقّع واجهة دفع موحّدة pay(amount)، ومزوّد الدفع الجديد يطلب createCharge({ cents, currency }). بدل تعديل كل مكان في الكود، تكتب Adapter واحدًا:

// مكتبة خارجية لا نتحكّم بها
class StripeLikeClient {
  createCharge({ cents, currency }) {
    console.log(`charge ${cents} ${currency}`);
  }
}

// الواجهة التي يتوقّعها نظامنا
class PaymentAdapter {
  constructor(client) { this.client = client; }
  pay(amount) {
    this.client.createCharge({ cents: Math.round(amount * 100), currency: "usd" });
  }
}

const gateway = new PaymentAdapter(new StripeLikeClient());
gateway.pay(12.5);   // charge 1250 usd

لو غيّرت المزوّد لاحقًا، تكتب Adapter جديدًا فقط، وبقية النظام لا يعرف بالتغيير.

نمط Facade (الواجهة المُوحَّدة)

يوفر واجهة مبسطة لنظام معقد من الكلاسات. يقلل من التعقيد والتبعيات.

class CPU:
    def process(self): return "CPU processing"

class Memory:
    def load(self): return "Loading data"

class HardDrive:
    def read(self): return "Reading data"

class ComputerFacade:
    def __init__(self):
        self.cpu = CPU()
        self.memory = Memory()
        self.hard_drive = HardDrive()

    def start(self):
        return f"{self.hard_drive.read()} -> {self.memory.load()} -> {self.cpu.process()}"

computer = ComputerFacade()
print(computer.start())

💡 Facade لا يمنع الوصول المباشر للأنظمة الداخلية: من يحتاج تحكّمًا دقيقًا يقدر يستخدم CPU أو Memory مباشرة. Facade مجرّد طريق مختصر للحالة الشائعة.

الفرق بين Facade و Adapter

FacadeAdapter
يبسّط واجهة موجودةيكيِّف واجهة غير متوافقة
يصمم واجهة جديدة مبسطةيحافظ على نفس الوظيفة
يقلل التبعياتيحل مشكلة التوافق

مثال Facade من الواقع

مكتبة axios هي Facade تخفي تعقيد XMLHttpRequest أو fetch وتقدم واجهة بسيطة.

الخلاصة

  • Adapter: يستخدم عندما تريد استخدام كلاس موجود لكن واجهته لا تتوافق مع ما يتوقعه النظام.
  • Facade: يستخدم عندما تريد تبسيط التفاعل مع نظام معقد.

🎯 التالي: نمط Template Method

شرح نمطا Adapter و Facade — أنماط التصميم (Design Patterns) بالعربي
نمطا Adapter و Facade — أنماط التصميم (Design Patterns) بالعربي · The Code Fix

📚 لمزيد من التعمّق في أنماط التصميم (Design Patterns)، راجِع البرمجة الكائنية على ويكيبيديا.

هل كان هذا الدرس مفيدًا؟