Menu
Coddy logo textTech

תבנית המתודה התבניתית

חלק מהיחידה תכנות מונחה עצמים במסלול ה-C# של Coddy. שיעור 59 מתוך 70.

תבנית שיטת התבנית היא תבנית התנהגותית שמגדירה את השלד של אלגוריתם במחלקת בסיס, ומאפשרת למחלקות יורשות לדרוס שלבים מסוימים בלי לשנות את המבנה הכולל. מחלקת הבסיס שולטת בזרימת העבודה, בעוד שמחלקות נגזרות מתאימות אישית חלקים בודדים.

התבנית הזאת משתמשת בירושה ובמתודות מופשטות. מחלקת הבסיס מכילה ״מתודת תבנית״ הקוראת לרצף של שלבים, שחלקם מופשטים ויש לממש אותם במחלקות־בת:

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 אידיאלית כשכמה מחלקות חולקות את אותו מבנה אלגוריתם, אך נבדלות בשלבים מסוימים. היא מעודדת שימוש חוזר בקוד על ידי הצבת הלוגיקה המשותפת במחלקת הבסיס, תוך מתן גמישות באמצעות מתודות שניתן לדרוס.

challenge icon

אתגר

קל

בואו נבנה מערכת ליצירת דוחות באמצעות תבנית Template Method. סוגים שונים של דוחות (כמו דוחות מכירות ודוחות מלאי) חולקים את אותו מבנה כללי — כולם צריכים לאסוף נתונים, לעצב אותם ולהפיק את התוצאה — אבל כל סוג דוח מטפל בשלבים האלה באופן שונה.

תארגנו את הקוד שלכם בשלושה קבצים:

  • ReportGenerator.cs: צרו מחלקה מופשטת ReportGenerator במרחב השמות Reporting. מחלקת הבסיס הזו מגדירה את השלד של האלגוריתם ליצירת דוחות באמצעות שיטת תבנית בשם Generate(). השיטה צריכה לקרוא לשלושה שלבים לפי הסדר: GatherData(), FormatReport() ו-OutputReport(). הגדירו את GatherData() ואת FormatReport() כמופשטות (כל סוג דוח יממש אותן באופן שונה), ואילו OutputReport() צריכה להיות שיטה וירטואלית עם מימוש ברירת מחדל שמדפיס 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, ודורסת את 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 מאפשרת לכם לקבוע אילו שלבים חובה לדרוס ואילו ניתן להתאים באופן אופציונלי!

נסו בעצמכם

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בחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר C# אונליין