Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

نمط المحول

جزء من قسم Object Oriented Programming في رحلة Dart على Coddy — الدرس 95 من 110.

يسمح نمط المحول (Adapter pattern) للواجهات غير المتوافقة بالعمل معاً. فهو يعمل كجسر بين فئتين لا يمكنهما التعاون بطريقة أخرى، حيث يقوم بتغليف فئة موجودة بواجهة جديدة يتوقعها العملاء. وهذا مفيد بشكل خاص عند دمج مكتبات الطرف الثالث أو الكود القديم (legacy code) في تطبيقك.

تخيل أن لديك نظاماً يعمل مع بيانات JSON، ولكنك تحتاج إلى دمج مكون يخرج بيانات XML فقط. بدلاً من تعديل أي من الفئتين (class)، تقوم بإنشاء محول (adapter) يترجم بينهما:

// الواجهة الحالية التي يتوقعها نظامك
abstract class JsonData {
  String getJson();
}

// فئة قديمة (Legacy) ذات واجهة غير متوافقة
class XmlService {
  String getXml() {
    return '<data><name>John</name></data>';
  }
}

// المحول (Adapter) يجعل XmlService متوافقاً مع JsonData
class XmlToJsonAdapter implements JsonData {
  final XmlService _xmlService;

  XmlToJsonAdapter(this._xmlService);

  @override
  String getJson() {
    String xml = _xmlService.getXml();
    // (تبسيط) JSON إلى XML تحويل الـ
    return '{"name": "John"}';
  }
}

void main() {
  var xmlService = XmlService();
  var adapter = XmlToJsonAdapter(xmlService);

  print(adapter.getJson());  // {"name": "John"}
}

يقوم XmlToJsonAdapter بتغليف XmlService ويقوم بتنفيذ واجهة JsonData. يعمل كود العميل مع واجهة JsonData المألوفة دون معرفة أن البيانات جاءت في الأصل من مصدر XML. يتولى المحول جميع عمليات الترجمة داخلياً.

استخدم نمط المحول (Adapter pattern) عندما تريد استخدام فئة (class) موجودة ولكن واجهتها (interface) لا تتطابق مع ما تحتاجه، أو عندما تحتاج إلى إنشاء فئة قابلة لإعادة الاستخدام تتعاون مع فئات ذات واجهات غير متوافقة.

challenge icon

التحدي

سهل

لنقم ببناء نظام محول لمشغل وسائط! تخيل أن لديك نظاماً صوتياً حديثاً يتوقع من جميع مصادر الوسائط توفير الصوت من خلال واجهة قياسية، ولكنك تحتاج إلى دمج مشغل سجلات فينيل (vinyl) قديم الطراز لديه طريقة مختلفة تماماً في إنتاج الصوت.

ستقوم بإنشاء ملفين لتنظيم تنفيذ نمط المحول (adapter pattern) الخاص بك:

  • media_adapter.dart: يحتوي هذا الملف على الواجهة (interface) وفئات المحول. قم بتعريف فئة مجردة (abstract class) باسم AudioSource يتوقعها نظامك الحديث - يجب أن تحتوي على طريقة String playAudio() تعيد مخرجات الصوت كسلسلة نصية. ثم قم بإنشاء فئة VinylPlayer تمثل المعدات القديمة - تحتوي على حقل trackName وطريقة String spinRecord() تعيد *crackle* Playing vinyl: [trackName] *crackle*. أخيراً، قم ببناء VinylAdapter يقوم بتنفيذ AudioSource ويغلف VinylPlayer. يجب أن تقوم طريقة playAudio() الخاصة بالمحول باستدعاء طريقة spinRecord() لمشغل الفينيل وإعادة النتيجة - مما يربط بين الواجهات غير المتوافقة.
  • main.dart: قم باستيراد ملف محول الوسائط الخاص بك ووضح كيف يجعل المحول مشغل الفينيل القديم يعمل مع الكود الذي يتوقع واجهة AudioSource الحديثة. قم بإنشاء VinylPlayer مع اسم المسار Bohemian Rhapsody. ثم قم بإنشاء VinylAdapter يغلف مشغل الفينيل هذا. قم بتخزين المحول في متغير من نوع AudioSource لإثبات أنه يتوافق مع الواجهة المتوقعة. استدعِ playAudio() على مصدر الصوت الخاص بك واطبع النتيجة.

جمال هذا النمط هو أن الكود الأساسي الخاص بك يعمل مع واجهة AudioSource القياسية - ولا يحتاج إلى معرفة أنه خلف الكواليس، يقوم مشغل فينيل قديم بالعمل الفعلي!

المخرجات المتوقعة:

*crackle* Playing vinyl: Bohemian Rhapsody *crackle*

ورقة مرجعية

يسمح نمط المحول (Adapter pattern) للواجهات غير المتوافقة بالعمل معاً من خلال العمل كجسر بين فئتين لا يمكنهما التعاون بطريقة أخرى.

يقوم المحول بتغليف فئة موجودة بواجهة جديدة يتوقعها العملاء، مما يجعله مفيداً عند دمج مكتبات خارجية أو أكواد قديمة (legacy code).

الهيكل الأساسي

// الواجهة المستهدفة التي يتوقعها العملاء
abstract class JsonData {
  String getJson();
}

// فئة موجودة بواجهة غير متوافقة
class XmlService {
  String getXml() {
    return '<data><name>John</name></data>';
  }
}

// المحول يجعل XmlService متوافقاً مع JsonData
class XmlToJsonAdapter implements JsonData {
  final XmlService _xmlService;

  XmlToJsonAdapter(this._xmlService);

  @override
  String getJson() {
    String xml = _xmlService.getXml();
    // تحويل XML إلى JSON
    return '{"name": "John"}';
  }
}

الاستخدام

void main() {
  var xmlService = XmlService();
  var adapter = XmlToJsonAdapter(xmlService);

  print(adapter.getJson());  // {"name": "John"}
}

يقوم المحول بتنفيذ الواجهة المستهدفة مع تغليف الفئة غير المتوافقة. يعمل كود العميل مع الواجهة المألوفة دون معرفة التنفيذ الأساسي.

متى يُستخدم: عندما تحتاج إلى استخدام فئة موجودة ولكن واجهتها لا تتطابق مع ما تحتاجه، أو عند إنشاء فئة قابلة لإعادة الاستخدام تتعاون مع فئات ذات واجهات غير متوافقة.

جرّب بنفسك

import 'media_adapter.dart';

void main() {
  // TODO: "Bohemian Rhapsody" باسم المسار VinylPlayer قم بإنشاء
  
  // TODO: VinylPlayer الذي يغلف VinylAdapter قم بإنشاء
  
  // TODO: AudioSource قم بتخزين المحول في متغير من نوع
  
  // TODO: الخاصة بمصدر الصوت لديك واطبع النتيجة playAudio() قم باستدعاء
  
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس Object Oriented Programming