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

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

جزء من قسم Object Oriented Programming في رحلة C# على Coddy — الدرس 59 من 70.

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

يستخدم هذا النمط الوراثة والأساليب المجردة. تحتوي الفئة الأساسية على "طريقة قالب" (template method) تستدعي تسلسلاً من الخطوات، بعضها مجرد ويجب تنفيذه بواسطة الفئات الفرعية:

public abstract class DataProcessor
{
    // طريقة القالب - تحدد هيكل الخوارزمية
    public void Process()
    {
        ReadData();
        ProcessData();
        SaveData();
    }
    
    protected abstract void ReadData();
    protected abstract void ProcessData();
    protected virtual void SaveData() => Console.WriteLine("Saving to default location");
}

public class CsvProcessor : DataProcessor
{
    protected override void ReadData() => Console.WriteLine("Reading CSV file");
    protected override void ProcessData() => Console.WriteLine("Parsing CSV data");
}

public class JsonProcessor : DataProcessor
{
    protected override void ReadData() => Console.WriteLine("Reading JSON file");
    protected override void ProcessData() => Console.WriteLine("Parsing JSON data");
    protected override void SaveData() => Console.WriteLine("Saving to cloud");
}

توفر كل فئة فرعية تنفيذها الخاص بينما تفرض الفئة الأساسية ترتيب العمليات:

DataProcessor csv = new CsvProcessor();
csv.Process();
// قراءة ملف CSV
// تحليل بيانات CSV
// الحفظ في الموقع الافتراضي

DataProcessor json = new JsonProcessor();
json.Process();
// قراءة ملف JSON
// تحليل بيانات JSON
// الحفظ في السحابة

نمط Template Method مثالي عندما تشترك فئات متعددة في نفس هيكل الخوارزمية ولكنها تختلف في خطوات محددة. فهو يعزز إعادة استخدام الكود من خلال وضع المنطق المشترك في الفئة الأساسية مع السماح بالمرونة من خلال الطرق القابلة للتجاوز (overridable methods).

challenge icon

التحدي

سهل

لنقم ببناء نظام لإنشاء التقارير باستخدام نمط Template Method. تشترك الأنواع المختلفة من التقارير (مثل تقارير المبيعات وتقارير المخزون) في نفس الهيكل العام - فجميعها تحتاج إلى جمع البيانات، وتنسيقها، وإخراج النتيجة - ولكن كل نوع من التقارير يتعامل مع هذه الخطوات بشكل مختلف.

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

  • ReportGenerator.cs: قم بإنشاء فئة مجردة (abstract class) باسم ReportGenerator داخل مساحة الأسماء Reporting. تحدد هذه الفئة الأساسية الهيكل العظمي لخوارزمية إنشاء التقرير من خلال "طريقة قالب" (template method) تسمى Generate(). يجب أن تستدعي هذه الطريقة ثلاث خطوات بالترتيب: GatherData()، و FormatReport()، و OutputReport(). اجعل GatherData() و FormatReport() مجردة (حيث سيقوم كل نوع تقرير بتنفيذها بشكل مختلف)، بينما يجب أن تكون OutputReport() طريقة افتراضية (virtual method) مع تنفيذ افتراضي يطبع Sending to default printer.
  • ConcreteReports.cs: قم بإنشاء فئتين ملموستين للتقارير في نفس مساحة الأسماء ترثان من ReportGenerator:
    • SalesReport - تقوم بتنفيذ GatherData() لطباعة Collecting sales data from database و FormatReport() لطباعة Formatting as sales summary
    • InventoryReport - تقوم بتنفيذ GatherData() لطباعة Scanning warehouse inventory، و FormatReport() لطباعة Formatting as inventory list، وتتجاوز (overrides) OutputReport() لطباعة Sending to warehouse manager
  • Program.cs: اجمع كل شيء معاً عن طريق إنشاء مثيلات للتقارير وتوليدها. تضمن "طريقة القالب" أن يتبع كل تقرير نفس العملية المكونة من ثلاث خطوات، ولكن السلوك المحدد لكل خطوة يختلف بناءً على نوع التقرير.

ستتلقى مدخلاً واحداً:

  • نوع التقرير: sales أو inventory

قم بإنشاء مولد التقارير المناسب بناءً على المدخلات واستدعِ طريقة Generate() الخاصة به.

على سبيل المثال، إذا كان المدخل هو sales، يجب أن يكون المخرج:

Collecting sales data from database
Formatting as sales summary
Sending to default printer

إذا كان المدخل هو inventory، يجب أن يكون المخرج:

Scanning warehouse inventory
Formatting as inventory list
Sending to warehouse manager

لاحظ كيف يتبع كلا التقريرين نفس هيكل الخوارزمية تماماً (الجمع، التنسيق، الإخراج)، ولكن يتم تخصيص تنفيذ كل خطوة. يستخدم SalesReport سلوك الإخراج الافتراضي، بينما يقوم InventoryReport بتجاوزه - مما يوضح كيف يتيح لك نمط Template Method التحكم في الخطوات الإلزامية للتجاوز والخطوات التي يمكن تخصيصها اختيارياً!

ورقة مرجعية

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

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

public abstract class DataProcessor
{
    // طريقة القالب - تحدد هيكل الخوارزمية
    public void Process()
    {
        ReadData();
        ProcessData();
        SaveData();
    }
    
    protected abstract void ReadData();
    protected abstract void ProcessData();
    protected virtual void SaveData() => Console.WriteLine("Saving to default location");
}

توفر الفئات الفرعية تطبيقاتها الخاصة بينما تفرض الفئة الأساسية ترتيب العمليات:

public class CsvProcessor : DataProcessor
{
    protected override void ReadData() => Console.WriteLine("Reading CSV file");
    protected override void ProcessData() => Console.WriteLine("Parsing CSV data");
}

public class JsonProcessor : DataProcessor
{
    protected override void ReadData() => Console.WriteLine("Reading JSON file");
    protected override void ProcessData() => Console.WriteLine("Parsing JSON data");
    protected override void SaveData() => Console.WriteLine("Saving to cloud");
}

الاستخدام:

DataProcessor csv = new CsvProcessor();
csv.Process();
// Reading CSV file
// Parsing CSV data
// Saving to default location

DataProcessor json = new JsonProcessor();
json.Process();
// Reading JSON file
// Parsing JSON data
// Saving to cloud

يعد نمط طريقة القالب مثالياً عندما تشترك فئات متعددة في نفس هيكل الخوارزمية ولكنها تختلف في خطوات محددة. فهو يعزز إعادة استخدام الكود من خلال وضع المنطق المشترك في الفئة الأساسية مع السماح بالمرونة من خلال الطرق القابلة للتجاوز.

جرّب بنفسك

using System;
using Reporting;

class Program
{
    public static void Main(string[] args)
    {
        string reportType = Console.ReadLine();
        
        // TODO: إنشاء منشئ التقارير المناسب بناءً على reportType
        // إذا كان reportType هو "sales"، فقم بإنشاء SalesReport
        // إذا كان reportType هو "inventory"، فقم بإنشاء InventoryReport
        // ثم استدعِ الدالة Generate() الخاصة بالتقرير
        
    }
}
quiz iconاختبر نفسك

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

جميع دروس Object Oriented Programming