מחלקות 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. אפשר לאטום רק מתודה שכבר הוגדרה כווירטואלית במחלקת אב. כך מתקבלת שליטה מדויקת: לאפשר התאמה אישית מסוימת בהיררכיית הירושה, ואז לנעול אותה בנקודה מסוימת.
אתגר
קלבואו נבנה מערכת לעיבוד תשלומים שמדגימה כיצד להשתמש ב־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 עבור כל אחד מהם והדפיסו את התוצאות
// כל תוצאה צריכה להופיע בשורה נפרדת
}
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות התכנות מונחה העצמים
קבצים חיצונייםמרחבי שמות והנחיותמבוא למחלקות ולאובייקטיםמילת המפתח 'this'מתודות ופרמטריםשדות לעומת מאפייניםבנאיםאתחול אובייקטיםסיכום – מחשבון פשוט4ירושה
תחביר ירושה בסיסית (:)מילת המפתח 'base'מילות המפתח Virtual ו-Overrideמחלקות Sealedמחלקת הבסיס 'object'סיכום – היררכיית עובדים7תכונות מתקדמות
העמסת אופרטוריםאינדקסרים (this[])דריסת ToString()מתודות הרחבהסיכום – רשימה מותאמת אישית2מאפיינים וחברים סטטיים
מאפיינים במימוש אוטומטימאפיינים לקריאה בלבד ולכתיבה בלבדשדות ומתודות סטטייםמחלקות סטטיותחברים עם גוף ביטוי5פולימורפיזם וממשקים
פולימורפיזם בזמן קומפילציה לעומת בזמן ריצהממשק לעומת מחלקה מופשטתממשקים מרוביםממשקים מפורשיםהמרה כלפי מעלה והמרה כלפי מטהחזרה: מחשבון צורות8מושגים מתקדמים בתכנות מונחה עצמים
קומפוזיציה במקום ירושהGenerics (מחלקות ומתודות)נציגים ואירועיםמאפיינים ורפלקציהIDisposable והצהרת usingיסודות הזרקת תלויותתרגלו בעצמכם: קומפיילר C# אונליין