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

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

جزء من قسم البرمجة كائنية التوجه في رحلة 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، مع السماح بالتخصيص عبر الوراثة.

challenge icon

التحدي

سهل

لنبنِ نظامًا لإنشاء المستندات باستخدام نمط 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()
        
    }
}
quiz iconاختبر نفسك

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

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

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