Menu
Coddy logo textTech

יסודות הזרקת תלויות

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

הזרקת תלויות (DI) היא טכניקה שבה מחלקה מקבלת את התלויות שלה מבחוץ במקום ליצור אותן בעצמה. כך הקוד נעשה גמיש יותר, ניתן לבדיקה ובעל צימוד רופף.

ללא הזרקת תלויות (DI), מחלקה יוצרת בעצמה את התלויות שלה, ולכן קשה לשנות או לבדוק אותה:

public class OrderService
{
    private EmailSender sender = new EmailSender();  // מצומד בחוזקה
    
    public void PlaceOrder() => sender.Send("Order placed");
}

עם DI, מעבירים תלויות דרך הבנאי:

public interface IMessageSender
{
    void Send(string message);
}

public class EmailSender : IMessageSender
{
    public void Send(string message) => Console.WriteLine("Email: " + message);
}

public class OrderService
{
    private IMessageSender sender;
    
    public OrderService(IMessageSender sender)
    {
        this.sender = sender;
    }
    
    public void PlaceOrder() => sender.Send("Order placed");
}

כעת OrderService אינו יודע ואינו צריך לדעת אם הוא משתמש בדוא״ל, ב-SMS או בשולח מדומה לצורך בדיקות. התלות "מוזרקת" בעת יצירת האובייקט:

IMessageSender emailSender = new EmailSender();
OrderService service = new OrderService(emailSender);
service.PlaceOrder();  // דוא״ל: ההזמנה בוצעה

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

challenge icon

אתגר

קל

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

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

  • ILogWriter.cs: הגדירו ממשק בשם ILogWriter במרחב השמות Logging. הממשק הזה מייצג את החוזה עבור כל יעד רישום, ועליו לכלול שיטה יחידה Write(string message) שמחזירה מחרוזת המתארת היכן נכתבה ההודעה.
  • LogWriters.cs: צרו שתי מחלקות מימוש קונקרטיות של ILogWriter במרחב השמות Logging:
    • ConsoleLogWriter — השיטה Write שלו מחזירה Console: {message}
    • FileLogWriter — מקבל שם קובץ דרך הבנאי שלו, והשיטה Write שלו מחזירה File[{filename}]: {message}
  • Logger.cs: צרו מחלקת Logger במרחב השמות Logging, שמקבלת את התלות שלה באמצעות הזרקה לבנאי. המחלקה Logger צריכה:
    • לקבל ILogWriter דרך הבנאי שלה ולאחסן אותו בשדה פרטי
    • להכיל שיטה Log(string message) שמעבירה את הקריאה לכותב שהוזרק ומחזירה את התוצאה
  • Program.cs: הדגימו הזרקת תלויות על ידי יצירת שני רישומים שונים — אחד עם ConsoleLogWriter ואחד עם FileLogWriter. הראו כיצד אותה מחלקת Logger מתנהגת באופן שונה בהתאם לתלות שמוזרקת אליה.

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

  • שם הקובץ עבור רושם הקבצים
  • ההודעה לרישום

צרו Logger עם ConsoleLogWriter ורשמו את ההודעה. לאחר מכן צרו Logger נוסף עם FileLogWriter (באמצעות שם הקובץ מהקלט) ורשמו את אותה הודעה. הדפיסו כל תוצאה בשורה נפרדת.

לדוגמה, אם הקלט הוא app.log ו-System started, הפלט צריך להיות:

Console: System started
File[app.log]: System started

שימו לב שמחלקת Logger לעולם אינה משתנה — היא עובדת עם כל מימוש של ILogWriter. זו המהות של הזרקת תלויות: Logger תלויה בהפשטה (הממשק), והמימוש הקונקרטי "מוזרק" מבחוץ. תוכלו להוסיף בקלות DatabaseLogWriter או CloudLogWriter בהמשך, בלי לשנות כלל את מחלקת Logger!

נסו בעצמכם

using System;
using Logging;

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

        // TODO: צרו Logger עם ConsoleLogWriter ורשמו את ההודעה ביומן
        // הדפיסו את התוצאה

        // TODO: צרו Logger נוסף עם FileLogWriter (באמצעות filename) ורשמו את אותה הודעה ביומן
        // הדפיסו את התוצאה
    }
}
quiz iconבחנו את עצמכם

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

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

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