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