Menu
Coddy logo textTech

קומפוזיציה במקום ירושה

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

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

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

public class MovementBehavior
{
    public void Move() => Console.WriteLine("Moving...");
}

public class AttackBehavior
{
    public void Attack() => Console.WriteLine("Attacking!");
}

public class Character
{
    private MovementBehavior movement = new MovementBehavior();
    private AttackBehavior attack = new AttackBehavior();
    
    public void Move() => movement.Move();
    public void Attack() => attack.Attack();
}

ההבדל המרכזי הוא הקשר. ירושה מייצגת „הוא־סוג־של” (כלב הוא בעל חיים), ואילו הרכבה מייצגת „יש־לו” (לדמות יש התנהגות תנועה). הרכבה מאפשרת להחליף התנהגויות בזמן ריצה, לשלב יכולות בחופשיות ולהימנע מבעיית מחלקת הבסיס השברירית.

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

challenge icon

אתגר

קל

בוא נבנה מערכת התראות שמדגימה את העוצמה של הרכבה לעומת הורשה. במקום ליצור היררכיה מורכבת של מחלקות התראות, תרכיבו NotificationSender על ידי מתן רכיבי התנהגות שניתן להחליף.

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

  • Behaviors.cs: צרו שתי מחלקות התנהגות במרחב השמות Notifications, המטפלות בהיבטים שונים של שליחת התראות:
    • FormattingBehavior - כוללת מתודה Format(string message) שמחזירה את ההודעה כשהיא עטופה ב-[ALERT] בתחילתה וב- [END] בסופה
    • DeliveryBehavior - כוללת מתודה Deliver(string channel, string message) שמחזירה מחרוזת בתבנית Sending via {channel}: {message}
  • NotificationSender.cs: צרו מחלקה NotificationSender במרחב השמות Notifications, שמשתמשת בהרכבה כדי לשלב התנהגויות. על השולח:
    • להכיל מופעים של FormattingBehavior ושל DeliveryBehavior כשדות פרטיים
    • להכיל מאפיין Channel (מחרוזת) ששומר את שם ערוץ המסירה
    • להכיל בנאי שמקבל את שם הערוץ
    • להכיל מתודה Send(string message) שמעצבת תחילה את ההודעה באמצעות התנהגות העיצוב, לאחר מכן מוסרת אותה באמצעות התנהגות המסירה ומחזירה את התוצאה הסופית
  • Program.cs: בקובץ הראשי, צרו NotificationSender עם ערוץ מהקלט, ולאחר מכן שלחו הודעה מהקלט. הדפיסו את התוצאה כדי להציג כיצד ההתנהגויות המשולבות פועלות יחד.

תקבלו שני קלטים:

  • שם ערוץ המסירה (למשל, Email, SMS)
  • ההודעה לשליחה

הדפיסו את התוצאה של קריאה ל-Send() על שולח ההתראות שלכם.

לדוגמה, אם הקלטים הם Email ו-Server is down, הפלט אמור להיות:

Sending via Email: [ALERT] Server is down [END]

שימו לב ש-NotificationSender לא יורשת משום מחלקה — היא פשוט "מכילה" התנהגויות של עיצוב ומסירה. גישת ההרכבה הזו מאפשרת להחליף בקלות כל אחת מההתנהגויות בלי לשנות את מחלקת השולח, או לעשות שימוש חוזר בהתנהגויות האלה במחלקות שונות לחלוטין!

נסו בעצמכם

using System;
using Notifications;

class Program
{
    public static void Main(string[] args)
    {
        // קראו את הקלט
        string channel = Console.ReadLine();
        string message = Console.ReadLine();

        // TODO: צרו NotificationSender עם הערוץ
        
        // TODO: שלחו את ההודעה והדפיסו את התוצאה
        
    }
}
quiz iconבחנו את עצמכם

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

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

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