# Interfaces — ממשקים📖 שיעור

## מה זה?

איך ממיינים `List<Student>` לפי גיל עם `.Sort()`? .NET לא יודע מה "לפני" ו"אחרי" אומר עבור `Student` שלכם — הוא לא מנחש. `IComparable` פותר את זה: "חוזה" (Interface) שאומר "כל טיפוס שמממש אותי יודע להשוות את עצמו למופע אחר מאותו סוג" — ו-`.Sort()` פשוט קורא לחוזה הזה, בלי לדעת שום דבר ספציפי על `Student`. בניגוד לירושה, אין כאן קשר "הוא-סוג-של" — `Student` ו-`Product` יכולים שניהם לממש `IComparable` בלי שום קשר אחד לשני.

## מילות מפתח שחשוב לזכור

• Interface — "חוזה": רשימת מתודות/Properties שכל מחלקה שמממשת אותו **מתחייבת** לספק, בלי מימוש משלה בתוך ה-Interface עצמו

• `implements` (בפועל: `: IInterfaceName`) — תחביר דומה לירושה, אך למחלקה מותר לממש כמה Interfaces יחד (בניגוד לירושה — רק Base Class אחת)

• `IComparable<T>` — Interface מובנה ב-.NET עם מתודה אחת, `CompareTo`, שמאפשרת מיון ו-`Sort()`

• Interface מול Abstract Class — Interface הוא חוזה טהור בלי מימוש כלל; Abstract Class יכולה להכיל גם מימוש משותף (ראו שיעור קודם)

```csharp
class Student : IComparable<Student>
{
    public string Name;
    public int Age;

    public Student(string name, int age)
    {
        Name = name;
        Age = age;
    }

    // The IComparable<Student> "contract" requires implementing CompareTo
    public int CompareTo(Student other)
    {
        return Age.CompareTo(other.Age);   // sort by age
    }
}

List<Student> students = new List<Student>
{
    new Student("Dana", 25),
    new Student("Avi", 20),
    new Student("Rotem", 30)
};

students.Sort();   // .NET calls CompareTo behind the scenes — no need to know how Student sorts
foreach (var s in students) Console.WriteLine($"{s.Name}: {s.Age}");
// Avi: 20, Dana: 25, Rotem: 30
```

```csharp
// Several interfaces together — unlike inheritance, more than one Base Class is allowed
interface IPrintable { void Print(); }
interface ISaveable { void Save(); }

class Report : IPrintable, ISaveable
{
    public void Print() => Console.WriteLine("Printing report...");
    public void Save() => Console.WriteLine("Saving report...");
}
```

## הסבר עיקרי

Interface מול Abstract Class — שתיהן "לא ניתנות ליצירה ישירה", אבל Abstract Class יכולה להכיל שדות ומתודות **עם מימוש** משותף (כמו `PrintArea` בשיעור הקודם), בעוד Interface (בגרסתו הקלאסי) הוא **רק** רשימת חתימות בלי שום מימוש — טהור "מה חייבים לספק", לא "איך". Abstract Class מתאימה לקשר "הוא-סוג-של" (Manager הוא-סוג-של Employee); Interface מתאים לקשר "יודע-לעשות" (Student יודע-להשוות-את-עצמו) בלי קשר משפחתי בין הטיפוסים.

למה `IComparable` שימושי כל כך — `List<T>.Sort()` ב-.NET **לא** יודע כלום על `Student` באופן ספציפי — היא כתובה גנרית לגמרי. היא רק דורשת ש-`T` ימלא את חוזה `IComparable<T>`. זו הסיבה שאותה `Sort()` בדיוק עובדת גם על `List<Student>`, גם על `List<Product>` וגם על `List<int>` — כולם (או שממשים את החוזה, או ש-.NET כבר יודע להשוות אותם, כמו `int`).

כמה Interfaces, Base Class אחת — מחלקה יכולה לרשת רק מ-Base Class **אחת** (C# לא תומכת בירושה מרובה), אבל לממש **כמה** Interfaces יחד — `class Report : IPrintable, ISaveable`. זו דרך גמישה לתאר "יכולות" מרובות בלי להיתקע בהיררכיית ירושה נוקשה.

## יתרונות

Interface מאפשר לטיפוסים לא-קשורים לחלוק "יכולת" משותפת בלי קשר משפחתי מלאכותי; קוד ספרייה (כמו `Sort()`) יכול לעבוד גנרית על כל טיפוס שממלא את החוזה, בלי לדעת עליו מראש; מחלקה יכולה לממש כמה Interfaces יחד, בניגוד למגבלת ה-Base Class היחידה.

## חסרונות

יותר מדי Interfaces קטנים ומפוזרים מדי עלולים להקשות על מעקב אחרי "מי בכלל מממש מה"; Interface טהור (בלי ברירות מחדל) מחייב מימוש מלא בכל מחלקה, גם אם ההתנהגות זהה בין רובן — שם Abstract Class עשויה להתאים יותר.

## נקודות חשובות

• Interface = חוזה טהור, בלי מימוש; Abstract Class יכולה להכיל מימוש משותף חלקי

• מחלקה יכולה לממש כמה Interfaces, אך לרשת רק מ-Base Class אחת

• `IComparable<T>.CompareTo` מאפשר ל-`.Sort()` למיין כל טיפוס בלי לדעת עליו מראש

• Interface מתאים לקשר "יודע-לעשות"; ירושה מתאימה לקשר "הוא-סוג-של"

## טעויות נפוצות

• לנסות לרשת משתי מחלקות בסיס — לא חוקי ב-C#, רק Interfaces מרובים מותרים

• לבחור ירושה כשבפועל אין קשר "הוא-סוג-של" אמיתי, רק "יכולת" משותפת — Interface מתאים יותר

• לשכוח לממש את כל חברי ה-Interface במחלקה — שגיאת קומפילציה עד שממשים הכל

## סיכום

Interface הוא "חוזה" טהור — רשימת מתודות/Properties שכל מחלקה שמממשת אותו מתחייבת לספק, בלי קשר משפחתי (ירושה) בין הטיפוסים. `IComparable<T>` הוא דוגמה מובנית ב-.NET: מימוש `CompareTo` מאפשר ל-`List<T>.Sort()` הגנרי למיין כל טיפוס, בלי לדעת עליו שום דבר ספציפי מראש. בניגוד לירושה (Base Class יחידה), מחלקה יכולה לממש כמה Interfaces יחד.

## דוקומנטציה רשמית

[Microsoft Learn — Interfaces](https://learn.microsoft.com/dotnet/csharp/fundamentals/types/interfaces)

[Microsoft Learn — IComparable&lt;T&gt;](https://learn.microsoft.com/dotnet/api/system.icomparable-1)

---

## תרגילים

### תרגיל 1 — IComparable

**המשימה:** הגדירו `class Product : IComparable<Product>` עם `Name` ו-`Price`, שממיין לפי `Price`. צרו `List<Product>` ומיינו אותה עם `.Sort()`.

**בדיקה:** אחרי `.Sort()`, המוצרים מסודרים מהזול ליקר.

### תרגיל 2 — כמה Interfaces

**המשימה:** הגדירו שני Interfaces: `IFlyable` (מתודה `Fly()`) ו-`ISwimmable` (מתודה `Swim()`). צרו `class Duck` שמממש את שניהם.

**בדיקה:** `duck.Fly()` ו-`duck.Swim()` שתיהן עובדות על אותו מופע `Duck`.

---

## פרויקט מסכם

**המשימה:** בנו מערכת ניהול משימות עם `IComparable<Task>` למיון לפי עדיפות.

**דרישות:**
1. `class Task : IComparable<Task>` עם `Title` (string) ו-`Priority` (int, מספר גבוה יותר = דחוף יותר)
2. `CompareTo` שממיין כך שעדיפות גבוהה תופיע **קודם** (מיון יורד, לא עולה כברירת מחדל)
3. `List<Task>` עם לפחות 4 משימות בעדיפויות שונות, מיון עם `.Sort()`, והדפסה בסדר הנכון

**בדיקה:** אחרי `.Sort()`, המשימה בעדיפות הגבוהה ביותר מופיעה ראשונה ברשימה המודפסת.

## מה בפרק הבא

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