نمط طريقة القالب
جزء من قسم البرمجة كائنية التوجه في رحلة Java على Coddy. الدرس 73 من 87.
إن نمط Template Method هو نمط تصميم سلوكي يحدّد هيكل خوارزمية في فئة أساسية، مما يسمح للفئات الفرعية بتجاوز خطوات محددة دون تغيير البنية العامة. فكّر فيه كوصفة: تظل عملية الطهي العامة كما هي، لكن يمكن أن تختلف المكونات أو التقنيات الفردية.
يستخدم النمط فئة abstract تحتوي على طريقة قالب تستدعي سلسلة من الخطوات. تحتوي بعض الخطوات على تطبيقات افتراضية، بينما تكون الخطوات الأخرى مجردة ويجب تنفيذها بواسطة الفئات الفرعية:
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");
}
}عادةً ما يتم وضع علامة final على طريقة القالب لمنع الفئات الفرعية من تغيير بنية الخوارزمية. عند استدعائها، تنفّذ التسلسل نفسه لجميع الفئات الفرعية:
DataProcessor csv = new CSVProcessor();
csv.process();
// المخرجات:
// قراءة ملف CSV
// تحليل بيانات CSV
// الحفظ في الموقع الافتراضييُعد نمط Template Method مثاليًا عندما تكون لديك خوارزميات تشترك في البنية نفسها، لكنها تختلف في خطوات محددة. وهو يعزز إعادة استخدام التعليمات البرمجية من خلال وضع المنطق المشترك في الفئة base، مع السماح بالتخصيص عبر الوراثة.
التحدي
سهللنبنِ نظامًا لإنشاء المستندات باستخدام نمط Template Method! ستنشئ إطارًا تتبع فيه أنواع مختلفة من المستندات (التقارير والفواتير) عملية الإنشاء نفسها، مع تخصيص خطوات محددة. وهذا مثالي للسيناريوهات التي يكون فيها سير العمل العام ثابتًا، بينما تختلف التفاصيل حسب نوع المستند.
ستنظّم التعليمات البرمجية الخاصة بك عبر أربعة ملفات:
DocumentGenerator.java: أنشئ الفئة الأساسية abstract التي تحدد طريقة القالب. يجب أن تحتويDocumentGeneratorعلى:طريقة
finalتُسمىgenerateDocument()وتحدد هيكل algorithm من خلال استدعاء ثلاث خطوات بالترتيب:createHeader()، ثمcreateBody()، ثمcreateFooter().طريقتين abstract:
createHeader()وcreateBody()، ويجب على الفئات الفرعية تنفيذهما.طريقة hook باسم
createFooter()مع تنفيذ افتراضي يطبع--- End of Document ---.ReportGenerator.java: أنشئ فئة فرعية Concrete لإنشاء التقارير. يجب أن تستقبل عنوان التقرير (String) من خلال constructor الخاص بها.تطبع الطريقة
createHeader()القيمة=== REPORT: [title] ===تطبع الطريقة
createBody()القيمةReport content goes here...استخدم footer الافتراضي الموروث.
InvoiceGenerator.java: أنشئ فئة فرعية Concrete أخرى لإنشاء الفواتير. يجب أن تستقبل اسم العميل (String) والمبلغ (double) من خلال constructor الخاص بها.تطبع الطريقة
createHeader()القيمة*** INVOICE ***تطبع الطريقة
createBody()القيمةCustomer: [name]في سطر واحد، ثمAmount Due: $[amount]في السطر التالي (نسّق المبلغ ليظهر بمنزلتين عشريتين).تجاوز
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 footer الافتراضي، بينما يوفر InvoiceGenerator footer خاصًا به. هذه هي قوة طرق hook في نمط Template Method!
جرّب بنفسك
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()
}
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
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أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط طريقة القالبنمط الحالةنمط التركيبنمط المكررتدرّب بنفسك: مترجم Java عبر الإنترنت