نمط طريقة القالب
جزء من قسم Object Oriented Programming في رحلة Java على Coddy — الدرس 73 من 87.
يُعد نمط طريقة القالب (Template Method Pattern) نمط تصميم سلوكي يحدد الهيكل العام لخوارزمية في فئة أساسية (base class)، مما يسمح للفئات الفرعية (subclasses) بإعادة تعريف خطوات معينة دون تغيير الهيكل العام. فكر في الأمر كأنه وصفة طعام: تظل عملية الطهي العامة كما هي، ولكن يمكن أن تختلف المكونات أو التقنيات الفردية.
يستخدم النمط فئة مجردة مع طريقة قالب (template method) تستدعي تسلسلاً من الخطوات. تمتلك بعض الخطوات تطبيقات افتراضية، بينما تكون الخطوات الأخرى مجردة ويجب تنفيذها بواسطة الفئات الفرعية:
abstract class DataProcessor {
// Template method - يحدد هيكل الخوارزمية
public final void process() {
readData();
processData();
saveData();
}
abstract void readData();
abstract void processData();
// التنفيذ الافتراضي (hook method)
void saveData() {
System.out.println("Saving to default location");
}
}
class CSVProcessor extends DataProcessor {
void readData() {
System.out.println("Reading CSV file");
}
void processData() {
System.out.println("Parsing CSV data");
}
}
class XMLProcessor extends DataProcessor {
void readData() {
System.out.println("Reading XML file");
}
void processData() {
System.out.println("Parsing XML data");
}
}عادةً ما يتم تمييز قالب الطريقة (template method) بكلمة final لمنع الفئات الفرعية من تغيير هيكل الخوارزمية. عند استدعائها، فإنها تنفذ نفس التسلسل لجميع الفئات الفرعية:
DataProcessor csv = new CSVProcessor();
csv.process();
// المخرجات:
// قراءة ملف CSV
// تحليل بيانات CSV
// الحفظ في الموقع الافتراضييعد نمط طريقة القالب (Template Method Pattern) مثاليًا عندما يكون لديك خوارزميات تشترك في نفس الهيكل ولكنها تختلف في خطوات محددة. فهو يعزز إعادة استخدام الكود من خلال وضع المنطق المشترك في الفئة الأساسية (base class) مع السماح بالتخصيص من خلال الوراثة (inheritance).
التحدي
سهللنقم ببناء نظام لإنشاء المستندات باستخدام نمط "Template Method Pattern"! ستقوم بإنشاء إطار عمل حيث تتبع أنواع المستندات المختلفة (التقارير والفواتير) نفس عملية الإنشاء ولكنها تخصص خطوات محددة. هذا مثالي للسيناريوهات التي يكون فيها سير العمل العام ثابتاً، ولكن التفاصيل تختلف حسب نوع المستند.
ستقوم بتنظيم الكود الخاص بك عبر أربعة ملفات:
DocumentGenerator.java: قم بإنشاء الفئة الأساسية المجردة (abstract base class) التي تحدد طريقة القالب (template method). يجب أن يحتويDocumentGeneratorعلى:طريقة
finalتسمىgenerateDocument()تحدد هيكل الخوارزمية من خلال استدعاء ثلاث خطوات بالترتيب:createHeader()، وcreateBody()، وcreateFooter().طريقتان مجردتان (abstract methods):
createHeader()وcreateBody()يجب على الفئات الفرعية تنفيذهما.طريقة خطاف (hook method) تسمى
createFooter()مع تنفيذ افتراضي يطبع--- End of Document ---.ReportGenerator.java: قم بإنشاء فئة فرعية ملموسة (concrete subclass) لإنشاء التقارير. يجب أن تأخذ عنوان التقرير (String) من خلال المنشئ (constructor) الخاص بها.طريقة
createHeader()تطبع=== REPORT: [title] ===طريقة
createBody()تطبعReport content goes here...استخدم التذييل الافتراضي الموروث.
InvoiceGenerator.java: قم بإنشاء فئة فرعية ملموسة أخرى لإنشاء الفواتير. يجب أن تأخذ اسم العميل (String) والمبلغ (double) من خلال المنشئ الخاص بها.طريقة
createHeader()تطبع*** INVOICE ***طريقة
createBody()تطبعCustomer: [name]في سطر واحد، ثمAmount Due: $[amount]في السطر التالي (قم بتنسيق المبلغ إلى منزلتين عشريتين).قم بإعادة تعريف (Override) لـ
createFooter()لطباعةThank you for your business!Main.java: اجمع نظام طريقة القالب الخاص بك معاً! ستتلقى ثلاثة مدخلات: عنوان التقرير (String)، واسم العميل (String)، ومبلغ الفاتورة (double).قم بإنشاء
ReportGeneratorبالعنوان واستدعِgenerateDocument(). اطبع سطراً فارغاً للفصل. ثم قم بإنشاءInvoiceGeneratorباسم العميل والمبلغ، واستدعِgenerateDocument().
ستتلقى ثلاثة مدخلات بالترتيب: عنوان التقرير (String)، واسم العميل (String)، ومبلغ الفاتورة (double).
على سبيل المثال، مع المدخلات Q4 Sales، و Acme Corp، و 1500.00، سيكون مخرجك هو:
=== REPORT: Q4 Sales ===
Report content goes here...
--- End of Document ---
*** INVOICE ***
Customer: Acme Corp
Amount Due: $1500.00
Thank you for your business!لاحظ كيف يتبع كلا نوعي المستندات نفس العملية المكونة من ثلاث خطوات والمحددة في طريقة القالب، ولكن كل منهما يخصص الخطوات بشكل مختلف. يستخدم ReportGenerator التذييل الافتراضي بينما يوفر InvoiceGenerator تذييله الخاص — هذه هي قوة طرق الخطاف (hook methods) في نمط "Template Method Pattern"!
ورقة مرجعية
نمط Template Method Pattern هو نمط تصميم سلوكي يحدد الهيكل العظمي لخوارزمية في فئة أساسية، مما يسمح للفئات الفرعية بتجاوز خطوات محددة دون تغيير الهيكل العام.
يستخدم هذا النمط فئة مجردة (abstract class) تحتوي على template method تستدعي تسلسلاً من الخطوات. بعض الخطوات لها تطبيقات افتراضية، بينما البعض الآخر مجرد ويجب تنفيذه بواسطة الفئات الفرعية:
abstract class DataProcessor {
// Template method - يحدد هيكل الخوارزمية
public final void process() {
readData();
processData();
saveData();
}
abstract void readData();
abstract void processData();
// تطبيق افتراضي (hook method)
void saveData() {
System.out.println("Saving to default location");
}
}تقوم الفئات الفرعية الملموسة بتنفيذ الأساليب المجردة:
class CSVProcessor extends DataProcessor {
void readData() {
System.out.println("Reading CSV file");
}
void processData() {
System.out.println("Parsing CSV data");
}
}يتم تمييز الـ template method بكلمة final لمنع الفئات الفرعية من تغيير هيكل الخوارزمية. عند استدعائها، فإنها تنفذ نفس التسلسل لجميع الفئات الفرعية:
DataProcessor csv = new CSVProcessor();
csv.process();
// المخرجات:
// Reading CSV file
// Parsing CSV data
// Saving to default locationالخصائص الرئيسية:
- الـ Template method تكون
finalوتحدد هيكل الخوارزمية - يجب تنفيذ الأساليب المجردة (Abstract methods) بواسطة الفئات الفرعية
- توفر أساليب الخطاف (Hook methods) تطبيقات افتراضية يمكن تجاوزها اختيارياً
- يعزز إعادة استخدام الكود من خلال وضع المنطق المشترك في الفئة الأساسية
جرّب بنفسك
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// قراءة المدخلات
String reportTitle = scanner.nextLine();
String customerName = scanner.nextLine();
double invoiceAmount = scanner.nextDouble();
// TODO: قم بإنشاء ReportGenerator بالعنوان واستدعاء generateDocument()
// TODO: اطبع سطراً فارغاً للفصل
// TODO: قم بإنشاء InvoiceGenerator باسم العميل والمبلغ، واستدعاء generateDocument()
}
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات الـ OOP
الملفات الخارجيةمقدمة في الـ OOPالفئات (Classes) مقابل الكائنات (Objects)الكلمة المفتاحية thisالدوال (Methods)الحقول (Attributes)دالة البناء (Constructor)تعدد أشكال دالة البناء (Constructor Overloading)مراجعة - آلة حاسبة بسيطة4الوراثة
الوراثة الأساسية (extends)الكلمة المفتاحية superإعادة تعريف الدوال (@Override)تسلسل المنشئات (Constructor Chaining)كلاس Objectالوراثة الأحادية ومتعددة المستوياتلماذا لا توجد وراثة متعددة للكلاساتمراجعة - هيكلية الموظفين7الدوال الخاصة وفئة Object
دالة toString()equals() و hashCode()دالة clone()compareTo() و Comparableواجهة Comparatorمراجعة - الترتيب المخصص2محددات الوصول والتغليف
نظرة عامة على مستويات الوصولدوال Getter و Setterإخفاء البياناتالكلمة المفتاحية finalمراجعة - مدير الحساب البنكي5تعدد الأشكال (Polymorphism)
أساسيات الـ Method Overloadingالـ Method Overriding (في وقت التشغيل)الـ Upcasting والـ Downcastingمعامل الـ instanceofالفئات والدوال المجردة (Abstract)مراجعة - حاسبة الأشكال8مفاهيم OOP المتقدمة
الـ Composition مقابل الـ Inheritanceالـ Aggregation مقابل الـ Compositionالفئات الداخلية والمتداخلة والمجهولة (Inner, Nested & Anonymous)الـ Enums ودوالهاالـ Records (Java 16+)الـ Sealed Classes (Java 17+)11أنماط التصميم - الجزء الأول
مقدمة في أنماط التصميمنمط Singletonنمط Factoryنمط Builderنمط Observerنمط Strategy3خصائص الفئة والعضو الساكن
المتغيرات الخاصة بالكائن مقابل المتغيرات الساكنةالدوال الساكنةالكتل البرمجية الساكنةالثوابت (static final)ملخص - العداد والأدوات المساعدة6الواجهات (Interfaces) والأصناف المجردة (Abstract Classes)
مقدمة في الواجهات (Interfaces)تنفيذ الواجهات (Interfaces)تنفيذ واجهات متعددةالـ Default و Static في الواجهاتالأصناف المجردة مقابل الواجهاتالواجهات الوظيفية (Functional Interfaces)مراجعة - نظام الدفع9الأنواع العامة (Generics)
مقدمة في الأنواع العامةالأصناف العامة (Generic Classes)الدوال العامة (Generic Methods)معاملات الأنواع المقيدةالرموز البديلة (?, extends, super)مراجعة - الحاويات العامة12أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط طريقة القالبنمط الحالةنمط التركيبنمط المكرر