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

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

جزء من قسم Object Oriented Programming في رحلة PHP على Coddy — الدرس 78 من 91.

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

فكر في إنشاء أنواع مختلفة من المستندات.

يتبع كل مستند نفس العملية: إنشاء الرأس، إضافة المحتوى، إنشاء التذييل. لكن تفاصيل كل خطوة تختلف حسب نوع المستند. تحدد طريقة القالب (template method) هذا التسلسل، بينما تقوم الفئات الفرعية (subclasses) بتنفيذ التفاصيل.

<?php
abstract class DocumentGenerator {
    // طريقة القالب - تحدد هيكل الخوارزمية
    public final function generate(): string {
        $output = $this->createHeader();
        $output .= $this->createContent();
        $output .= $this->createFooter();
        return $output;
    }
    
    // الخطوات التي يجب تنفيذها بواسطة الفئات الفرعية
    abstract protected function createHeader(): string;
    abstract protected function createContent(): string;
    abstract protected function createFooter(): string;
}

class HtmlDocument extends DocumentGenerator {
    protected function createHeader(): string {
        return "<html><head></head><body>";
    }
    
    protected function createContent(): string {
        return "<p>Hello World</p>";
    }
    
    protected function createFooter(): string {
        return "</body></html>";
    }
}

class TextDocument extends DocumentGenerator {
    protected function createHeader(): string {
        return "=== DOCUMENT ===\n";
    }
    
    protected function createContent(): string {
        return "Hello World\n";
    }
    
    protected function createFooter(): string {
        return "=== END ===";
    }
}

$html = new HtmlDocument();
echo $html->generate() . "\n";

$text = new TextDocument();
echo $text->generate();

المخرجات:

<html><head></head><body><p>Hello World</p></body></html>
=== DOCUMENT ===
Hello World
=== END ===

لاحظ الكلمة المفتاحية final في طريقة القالب (template method). هذا يمنع الفئات الفرعية من تغيير هيكل الخوارزمية. هذا النمط مثالي عندما يكون لديك فئات متعددة تتبع نفس سير العمل ولكنها تختلف في تفاصيل التنفيذ. إضافة نوع مستند جديد يعني إنشاء فئة فرعية جديدة دون المساس بالكود الحالي.

challenge icon

التحدي

سهل

لنقم ببناء نظام لإنشاء التقارير باستخدام نمط طريقة القالب (Template Method Pattern). تتبع الأنواع المختلفة من التقارير نفس الهيكل — قسم العنوان، وقسم البيانات، وقسم الملخص — ولكن كل نوع تقرير ينسق هذه الأقسام بشكل مختلف. ستحدد "طريقة القالب" سير العمل هذا بينما تقوم الفئات الفرعية بتخصيص كل خطوة.

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

  • ReportGenerator.php — أنشئ فئة مجردة (abstract class) باسم ReportGenerator تحدد الهيكل العظمي لخوارزمية إنشاء التقرير. يجب أن تقوم فئتك بما يلي:
    • تقبل عنوان التقرير في منشئها (استخدم خاصية constructor promotion)
    • تحتوي على طريقة عامة نهائية (final public method) باسم generate(): string تستدعي ثلاث خطوات بالترتيب: createTitle()، و createBody()، و createSummary()، مع دمج نتائجها
    • تصرح عن ثلاث طرق مجردة محمية (abstract protected methods) يجب على الفئات الفرعية تنفيذها: createTitle(): string، و createBody(): string، و createSummary(): string
  • HtmlReport.php — قم بتضمين ملف ReportGenerator وأنشئ فئة HtmlReport ترث منها. يقوم هذا التقرير بتنسيق المخرجات كـ HTML:
    • createTitle() تعيد "<h1>" . $this->title . "</h1>"
    • createBody() تعيد "<p>Report data goes here</p>"
    • createSummary() تعيد "<footer>End of report</footer>"
  • PlainTextReport.php — قم بتضمين ملف ReportGenerator وأنشئ فئة PlainTextReport ترث منها. يستخدم هذا التقرير تنسيق نصي بسيط:
    • createTitle() تعيد "### " . $this->title . " ###\n"
    • createBody() تعيد "Report data goes here\n"
    • createSummary() تعيد "--- End of report ---"
  • main.php — قم بتضمين كلا ملفي التقارير. ستتلقى مدخلين: نوع التقرير ("html" أو "text") وعنوان التقرير.

    بناءً على نوع التقرير، أنشئ منشئ التقارير المناسب بالعنوان المعطى. استدعِ generate() واطبع التقرير كاملاً.

يضمن نمط طريقة القالب (Template Method Pattern) أن تتبع جميع التقارير نفس الهيكل المكون من ثلاث خطوات مع السماح لكل نوع تقرير بتنسيق أقسامه بشكل فريد. تمنع الكلمة المفتاحية final في generate() الفئات الفرعية من تغيير تسلسل الخوارزمية — حيث يمكنهم فقط تخصيص الخطوات الفردية.

ورقة مرجعية

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

تحتوي الفئة الأساسية على طريقة قالب (template method) تتحكم في تسلسل سير العمل. عادةً ما يتم تمييز هذه الطريقة بكلمة final لمنع الفئات الفرعية من تعديل هيكل الخوارزمية.

تقوم الفئات الفرعية بتنفيذ الطرق المجردة (abstract methods) لتخصيص الخطوات الفردية للخوارزمية.

<?php
abstract class DocumentGenerator {
    // طريقة القالب - تحدد هيكل الخوارزمية
    public final function generate(): string {
        $output = $this->createHeader();
        $output .= $this->createContent();
        $output .= $this->createFooter();
        return $output;
    }
    
    // خطوات مجردة لتقوم الفئات الفرعية بتنفيذها
    abstract protected function createHeader(): string;
    abstract protected function createContent(): string;
    abstract protected function createFooter(): string;
}

class HtmlDocument extends DocumentGenerator {
    protected function createHeader(): string {
        return "<html><head></head><body>";
    }
    
    protected function createContent(): string {
        return "<p>Hello World</p>";
    }
    
    protected function createFooter(): string {
        return "</body></html>";
    }
}

$html = new HtmlDocument();
echo $html->generate();

الخصائص الرئيسية:

  • يتم تمييز طريقة القالب بكلمة final لمنع تعديل هيكل الخوارزمية
  • تحدد الطرق المجردة (Abstract methods) نقاط التخصيص للفئات الفرعية
  • مثالي عندما تتبع فئات متعددة نفس سير العمل ولكنها تختلف في تفاصيل التنفيذ
  • إضافة متغيرات جديدة تتطلب فقط إنشاء فئات فرعية جديدة دون تعديل الكود الحالي

جرّب بنفسك

<?php

require_once 'HtmlReport.php';
require_once 'PlainTextReport.php';

// قراءة المدخلات
$reportType = trim(fgets(STDIN));
$reportTitle = trim(fgets(STDIN));

// TODO: بناءً على نوع التقرير ("html" أو "text")،
// قم بإنشاء مولد التقارير المناسب بالعنوان المعطى

// TODO: قم باستدعاء generate() واطبع التقرير كاملاً

?>
quiz iconاختبر نفسك

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

جميع دروس Object Oriented Programming