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

نمط المحول

جزء من قسم البرمجة كائنية التوجه في رحلة Dart على Coddy. الدرس 95 من 110.

يسمح نمط Adapter للواجهات غير المتوافقة بالعمل معًا. ويعمل كجسر بين فئتين لا يمكنهما التعاون لولا ذلك، إذ يغلّف فئة موجودة بواجهة جديدة يتوقعها clients. ويكون هذا مفيدًا بشكل خاص عند دمج مكتبات تابعة لجهات خارجية أو تعليمات برمجية legacy في تطبيقك.

تخيّل أن لديك نظامًا يعمل مع بيانات JSON، لكنك تحتاج إلى دمج مكوّن لا يُخرج إلا XML. بدلًا من تعديل أيٍّ من class، تنشئ adapter يترجم بينهما:

// الواجهة الموجودة التي يتوقعها نظامك
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"}
}

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

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

challenge icon

التحدي

سهل

لنبنِ نظام adapter لمشغّل وسائط! تخيّل أن لديك نظام audio حديثًا يتوقّع من جميع مصادر الوسائط توفير الصوت من خلال interface قياسي، لكنك تحتاج إلى دمج مشغّل أسطوانات فينيل قديم يتبع طريقة مختلفة تمامًا لإنتاج الصوت.

ستنشئ ملفين لتنظيم تنفيذ نمط adapter لديك:

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

يكمن جمال هذا النمط في أن code الرئيسي لديك يعمل مع interface AudioSource القياسي — ولا يحتاج إلى معرفة أن مشغّل فينيل قديمًا ينفّذ العمل الفعلي خلف الكواليس!

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

*crackle* Playing vinyl: Bohemian Rhapsody *crackle*

جرّب بنفسك

import 'media_adapter.dart';

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

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

جميع دروس البرمجة كائنية التوجه

تدرّب بنفسك: مترجم Dart عبر الإنترنت