نمط طريقة القالب
جزء من قسم 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).
التحدي
سهللنقم ببناء نظام لإنشاء التقارير باستخدام نمط 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 summaryInventoryReport- تقوم بتنفيذ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() الخاصة بالتقرير
}
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات OOP
الملفات الخارجيةNamespaces والتوجيهاتمقدمة في Classes و Objectsالكلمة المفتاحية 'this'Methods والمعاملاتFields مقابل PropertiesConstructorsObject Initializersمراجعة - آلة حاسبة بسيطة4الوراثة
صيغة الوراثة الأساسية (:)الكلمة المفتاحية 'base'الكلمات المفتاحية Virtual و Overrideالأصناف المختومة (Sealed Classes)الفئة الأساسية 'object'مراجعة - هيكلية الموظفين7ميزات متقدمة
تحميل العوامل (Operator Overloading)المفهرسات (Indexers (this[]))إعادة تعريف ()ToStringدوال التوسعة (Extension Methods)ملخص - Custom List2الخصائص والأعضاء الساكنة (Static Members)
الخصائص المطبقة تلقائيًا (Auto-Implemented Properties)خصائص القراءة فقط والكتابة فقطالحقول والدوال الساكنة (Static)الفئات الساكنة (Static Classes)الأعضاء ذات البنية التعبيرية (Expression-Bodied Members)5تعدد الأشكال والواجهات (Polymorphism & Interfaces)
تعدد الأشكال: وقت التجميع مقابل وقت التشغيلالواجهة مقابل الفئة المجردة (Abstract Class)الواجهات المتعددةالواجهات الصريحةUpcasting و Downcastingملخص - حاسبة الأشكال8مفاهيم البرمجة كائنية التوجه (OOP) المتقدمة
التركيب بدلاً من الوراثةالـ Generics (الأصناف والدوال)الـ Delegates والأحداثالـ Attributes والـ Reflectionواجهة IDisposable وجملة usingأساسيات Dependency Injection