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

نمط طريقة القالب

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

يحدد نمط طريقة القالب (Template Method pattern) الهيكل العام لخوارزمية في فئة أساسية، مما يسمح للفئات الفرعية بإعادة تعريف خطوات معينة دون تغيير الهيكل العام. تتحكم الفئة الأساسية في سير العمل، بينما تقوم الفئات الفرعية بتخصيص الخطوات الفردية.

يستخدم هذا النمط الوراثة: حيث تُعرّف فئة مجردة (abstract class) "طريقة قالب" (template method) تستدعي سلسلة من الخطوات، بعضها يكون مجرداً (يجب تنفيذه بواسطة الفئات الفرعية) وبعضها الآخر له تنفيذات افتراضية:

abstract class DataProcessor {
  // Template method - يحدد هيكل الخوارزمية
  void process() {
    readData();
    processData();
    saveData();
  }

  void readData();      // Abstract - يجب على الفئات الفرعية تنفيذها
  void processData();   // Abstract - يجب على الفئات الفرعية تنفيذها

  void saveData() {     // تنفيذ افتراضي
    print('Data saved to database');
  }
}

class CsvProcessor extends DataProcessor {
  @override
  void readData() => print('Reading CSV file');

  @override
  void processData() => print('Parsing CSV rows');
}

class JsonProcessor extends DataProcessor {
  @override
  void readData() => print('Reading JSON file');

  @override
  void processData() => print('Parsing JSON objects');

  @override
  void saveData() => print('Saved to cloud storage');
}

void main() {
  var csv = CsvProcessor();
  csv.process();
  // Reading CSV file
  // Parsing CSV rows
  // Data saved to database

  var json = JsonProcessor();
  json.process();
  // Reading JSON file
  // Parsing JSON objects
  // Saved to cloud storage
}

تُعد الطريقة process() هي القالب - فهي تحدد ترتيب العمليات. تقوم الفئات الفرعية بتنفيذ readData() و processData() بشكل مختلف، ويمكنها اختيارياً تجاوز saveData(). الفائدة الرئيسية هي أن هيكل الخوارزمية يظل ثابتاً عبر جميع التنفيذات مع السماح بالمرونة في الخطوات الفردية.

challenge icon

التحدي

سهل

لنقم ببناء نظام لإنشاء التقارير باستخدام نمط Template Method! ستقوم بإنشاء إطار عمل تتبع فيه أنواع التقارير المختلفة نفس الهيكل العام، ولكن يقوم كل نوع تقرير بتخصيص خطوات محددة مثل جمع البيانات وتنسيق المخرجات.

ستقوم بتنظيم الكود الخاص بك في ملفين:

  • report_generator.dart: يحتوي هذا الملف على الفئة الأساسية المجردة (abstract base class) وتطبيقات التقارير الملموسة (concrete implementations). قم بإنشاء فئة مجردة باسم ReportGenerator مع تابع قالب (template method) يسمى generate() يحدد سير عمل إنشاء التقرير بهذا الترتيب: fetchData()، و analyzeData()، و formatReport()، و deliver(). يجب أن تكون التوابع fetchData() و formatReport() مجردة (حيث يتعامل كل نوع تقرير معها بشكل مختلف)، بينما يجب أن يطبع analyzeData() النص Analyzing data... ويطبع deliver() النص Report delivered via email. كتطبيقات افتراضية. ثم قم بإنشاء فئتين ملموستين للتقارير:
    • SalesReport - يطبع التابع fetchData() الخاص بها Fetching sales data from database... ويطبع التابع formatReport() الخاص بها Formatting as bar charts and tables.
    • InventoryReport - يطبع التابع fetchData() الخاص بها Fetching inventory levels from warehouse...، ويطبع التابع formatReport() الخاص بها Formatting as inventory list.، وتقوم بإعادة تعريف (override) التابع deliver() ليطبع Report sent to warehouse manager.
  • main.dart: قم باستيراد ملف منشئ التقارير واستعرض كيف يحافظ نمط Template Method على اتساق هيكل الخوارزمية مع السماح بالتخصيص. قم بإنشاء كائن من SalesReport واستدعِ تابع generate() الخاص به. ثم اطبع سطرًا فارغًا للفصل. قم بإنشاء كائن من InventoryReport واستدعِ تابع generate() الخاص به أيضًا.

لاحظ كيف يتبع كلا التقريرين نفس العملية المكونة من أربع خطوات، ولكن كل منهما يخصص الخطوات التي تهم غرضه المحدد. حتى أن InventoryReport يقوم بإعادة تعريف طريقة التسليم الافتراضية لإرسال التقارير إلى مستلم مختلف!

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

Fetching sales data from database...
Analyzing data...
Formatting as bar charts and tables.
Report delivered via email.

Fetching inventory levels from warehouse...
Analyzing data...
Formatting as inventory list.
Report sent to warehouse manager.

ورقة مرجعية

يحدد نمط طريقة القالب (Template Method pattern) الهيكل العظمي لخوارزمية في فئة أساسية، مما يسمح للفئات الفرعية بتجاوز خطوات محددة دون تغيير الهيكل العام.

تُعرف الفئة المجردة (abstract class) "طريقة قالب" تستدعي تسلسلاً من الخطوات. بعض الخطوات تكون مجردة (يجب تنفيذها بواسطة الفئات الفرعية) وبعضها يحتوي على تنفيذات افتراضية:

abstract class DataProcessor {
  // طريقة القالب - تحدد هيكل الخوارزمية
  void process() {
    readData();
    processData();
    saveData();
  }

  void readData();      // مجردة - يجب على الفئات الفرعية تنفيذها
  void processData();   // مجردة - يجب على الفئات الفرعية تنفيذها

  void saveData() {     // تنفيذ افتراضي
    print('Data saved to database');
  }
}

class CsvProcessor extends DataProcessor {
  @override
  void readData() => print('Reading CSV file');

  @override
  void processData() => print('Parsing CSV rows');
}

class JsonProcessor extends DataProcessor {
  @override
  void readData() => print('Reading JSON file');

  @override
  void processData() => print('Parsing JSON objects');

  @override
  void saveData() => print('Saved to cloud storage');
}

تتحكم "طريقة القالب" في ترتيب سير العمل. تقوم الفئات الفرعية بتخصيص الخطوات الفردية من خلال تنفيذ الطرق المجردة وتجاوز التنفيذات الافتراضية اختيارياً. يظل هيكل الخوارزمية ثابتاً عبر جميع التنفيذات.

جرّب بنفسك

import 'report_generator.dart';

void main() {
  // TODO: قم بإنشاء SalesReport واستدعاء التابع generate() الخاص به

  // TODO: اطبع سطرًا فارغًا للفصل

  // TODO: قم بإنشاء InventoryReport واستدعاء التابع generate() الخاص به
}
quiz iconاختبر نفسك

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

جميع دروس Object Oriented Programming