Menu
Coddy logo textTech

מחלקות Sealed

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

לפעמים רוצים לעצור את שרשרת הירושה. מילת המפתח sealed מונעת ירושה ממחלקה ומקבעת את המימוש שלה, כך שאף מחלקה אחרת לא תוכל לרשת ממנה.

public sealed class FinalDog : Animal
{
    public override void Speak()
    {
        Console.WriteLine("Woof!");
    }
}

// זה יגרום לשגיאת קומפילציה:
// public class SuperDog : FinalDog { }

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

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

public class Dog : Animal
{
    public sealed override void Speak()
    {
        Console.WriteLine("Woof!");
    }
}

public class Puppy : Dog
{
    // אי אפשר לדרוס את Speak() - היא sealed
    // אבל אפשר להוסיף מתודות חדשות
    public void Whimper()
    {
        Console.WriteLine("Whimper...");
    }
}

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

challenge icon

אתגר

קל

בואו נבנה מערכת לעיבוד תשלומים שמדגימה כיצד להשתמש ב־sealed כדי לנעול מימושים קריטיים. תיצרו היררכיה שבה ניתן להרחיב שיטות תשלום מסוימות, אך שיטות התשלום המאובטחות ביותר אטומות כדי למנוע שינויים כלשהם.

תיצרו ארבעה קבצים כדי לארגן את הקוד:

  • PaymentMethod.cs: הגדירו מחלקה בשם PaymentMethod במרחב השמות Payments. למחלקת הבסיס הזו יש מאפיין Name (מחרוזת) ובנאי שמגדיר אותו. כללו שיטה בשם ProcessPayment(decimal amount) עם מילת המפתח virtual, שמחזירה את "Processing ${amount} via {Name}".
  • CreditCardPayment.cs: הגדירו מחלקה בשם CreditCardPayment במרחב השמות Payments, שיורשת מ־PaymentMethod. הוסיפו מאפיין CardNumber (מחרוזת). הבנאי מקבל שם ומספר כרטיס, ומשתמש ב־base כדי להעביר את השם. דרסו את ProcessPayment באמצעות מילת המפתח sealed, כך שאף מחלקה יורשת לא תוכל לשנות את ההתנהגות הזו. היא אמורה להחזיר את "Charging ${amount} to card ending in {last 4 digits of CardNumber}".
  • BankTransfer.cs: הגדירו מחלקה בשם BankTransfer עם מילת המפתח sealed במרחב השמות Payments, שיורשת מ־PaymentMethod. המחלקה כולה אטומה — אף מחלקה לא יכולה לרשת ממנה. הוסיפו מאפיין BankName (מחרוזת). הבנאי מקבל שם ושם בנק. דרסו את ProcessPayment כך שתחזיר את "Transferring ${amount} from {BankName}".
  • Program.cs: בקובץ הראשי שלכם, צרו מופעים של שלושת סוגי התשלום באמצעות ערכי קלט. שמרו אותם בהפניות מסוג PaymentMethod וקראו ל־ProcessPayment עבור כל אחד מהם, כדי להדגים פולימורפיזם עם מימושים אטומים.

תקבלו ארבעה ערכי קלט:

  • מספר כרטיס אשראי (16 ספרות)
  • שם הבנק
  • סכום התשלום

הדפיסו את התוצאה של עיבוד תשלום באמצעות כל אחת מהשיטות:

{base PaymentMethod result}
{CreditCardPayment result}
{BankTransfer result}

לדוגמה, אם הקלט הוא 1234567890123456, First National ו־150.00, הפלט אמור להיות:

Processing $150.00 via Generic
Charging $150.00 to card ending in 3456
Transferring $150.00 from First National

השתמשו ב־"Generic" כשם למופע הבסיס של PaymentMethod, ב־"Credit Card" עבור תשלום בכרטיס אשראי, וב־"Bank Transfer" עבור העברה בנקאית.

השיטה האטומה ב־CreditCardPayment מבטיחה שאם מישהו ייצור מחלקת משנה, הוא לא יוכל לשנות את אופן עיבוד התשלומים בכרטיס אשראי. המחלקה האטומה BankTransfer מונעת כל ירושה — שתי השיטות האלה הן דפוסי אבטחה חשובים במערכות תשלומים!

נסו בעצמכם

using System;
using Payments;

class Program
{
    public static void Main(string[] args)
    {
        // קראו את הקלטים
        string cardNumber = Console.ReadLine();
        string bankName = Console.ReadLine();
        decimal amount = Convert.ToDecimal(Console.ReadLine());
        
        // TODO: צרו מופע בסיסי של PaymentMethod עם השם "Generic"
        // שמרו אותו כהפניה מסוג PaymentMethod
        
        // TODO: צרו מופע של CreditCardPayment עם השם "Credit Card" ומספר הכרטיס
        // שמרו אותו כהפניה מסוג PaymentMethod
        
        // TODO: צרו מופע של BankTransfer עם השם "Bank Transfer" ושם הבנק
        // שמרו אותו כהפניה מסוג PaymentMethod
        
        // TODO: קראו ל-ProcessPayment עבור כל אחד מהם והדפיסו את התוצאות
        // כל תוצאה צריכה להופיע בשורה נפרדת
    }
}
quiz iconבחנו את עצמכם

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

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

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