Smart-World Surf

יחידה 9: תכנות מונחה עצמים (OOP)

ארגון קוד סביב אובייקטים ומחלקות.

ברוכים הבאים לשיעור בנושא "תכנות מונחה עצמים (OOP)" במסגרת הקורס "יסודות מדעי המחשב" (371.1.1601) בבן-גוריון. יחידה זו היא אבן יסוד בהבנת ארגון קוד מודרני, והיא קריטית ליכולתכם לפתח מערכות תוכנה מורכבות, ניתנות לתחזוקה ולהרחבה. בבחינות בבן-גוריון, הדגש הוא לרוב על הבנה מעמיקה של העקרונות ויישומם בפועל, כולל יכולת לנתח קוד קיים, להשלים קטעי קוד חסרים (כמו בקבצי ה-skeleton שראיתם בתרגילים), ולתכנן היררכיות מחלקות נכונות לפתרון בעיות נתונות.

יסודות תכנות מונחה עצמים (OOP)

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

מחלקה (Class): תבנית או "תוכנית" ליצירת אובייקטים. היא מגדירה את התכונות (נתונים) וההתנהגויות (פעולות/מתודות) המשותפות לכל האובייקטים מסוג זה.
אובייקט (Object): מופע ספציפי של מחלקה. לכל אובייקט יש מצב משלו (ערכים ספציפיים לתכונות שלו) והוא יכול לבצע את הפעולות שהוגדרו במחלקה שלו.
תכונה (Attribute): משתנה המוגדר בתוך מחלקה ומייצג מאפיין של האובייקט (לדוגמה, שם, גיל, צבע).
מתודה (Method): פונקציה המוגדרת בתוך מחלקה ומייצגת התנהגות או פעולה שאובייקט יכול לבצע (לדוגמה, הדפסה, חישוב, שינוי מצב).

עקרונות הליבה של OOP

ארבעת עמודי התווך של OOP הם אלו המאפשרים את היתרונות הגלומים בפרדיגמה זו:

כימוס (Encapsulation)

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

הורשה (Inheritance)

מנגנון המאפשר למחלקה חדשה (מחלקה נגזרת / בן) לרשת תכונות ומתודות ממחלקה קיימת (מחלקה בסיס / אב). זה מקדם שימוש חוזר בקוד ומבסס היררכיה של יחסים מסוג "הוא-א" (is-a), לדוגמה: "כלב הוא-א חיה".

פולימורפיזם (Polymorphism)

היכולת של אובייקטים שונים להגיב לאותה קריאה למתודה בצורות שונות, בהתאם לסוגם. ב-Python, זה מתבטא בעיקר באמצעות Duck Typing ועקיפה של מתודות (Method Overriding) במחלקות נגזרות.

הפשטה (Abstraction)

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

יישום ב-Python ודוגמאות נפוצות

Python היא שפה מונחית עצמים מובהקת. כל דבר ב-Python הוא אובייקט, ומחלקות הן הדרך שלנו להגדיר סוגי אובייקטים חדשים.

  • הגדרת מחלקה: משתמשים במילת המפתח class.
    class Point:
        def __init__(self, x, y):
            self.x = x
            self.y = y
    
        def distance_from_origin(self):
            return (self.x**2 + self.y**2)**0.5
  • מתודת __init__: קונסטרוקטור, נקראת אוטומטית בעת יצירת אובייקט חדש. היא מקבלת את self כארגומנט הראשון (המתייחס למופע הנוכחי של האובייקט).
  • self: המוסכמה ב-Python להתייחסות למופע הנוכחי של המחלקה. דרכו ניגשים לתכונות ולמתודות של האובייקט.
  • תכונות מופע מול תכונות מחלקה: תכונות מופע (self.x) שייכות לכל אובייקט בנפרד. תכונות מחלקה (מוגדרות ישירות תחת המחלקה, מחוץ למתודות) משותפות לכל מופעי המחלקה.
  • הורשה: מחלקה יורשת ממחלקה אחרת על ידי ציון שם מחלקת האב בסוגריים.
    class ColoredPoint(Point):
        def __init__(self, x, y, color):
            super().__init__(x, y) # קורא לקונסטרוקטור של מחלקת האב
            self.color = color
    
        def __str__(self): # עקיפת מתודה
            return f"({self.x}, {self.y}) with color {self.color}"

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

דגשים לבחינה וטעויות נפוצות

הבנת זרימת הביצוע בהורשה ופולימורפיזם: נושא זה הוא מוקד קבוע לשאלות בבחינות. ודאו שאתם מבינים היטב מתי נקרא הקונסטרוקטור של מחלקת האב (באמצעות super().__init__()), ואיזו גרסה של מתודה נקראת כאשר יש עקיפה (overriding) במחלקות נגזרות. זכרו ש-Python מחפשת את המתודה תחילה במחלקה הנוכחית, ואז במחלקות האב בסדר היררכי. שאלות רבות יכללו קוד עם היררכיות מחלקות ויבקשו מכם לחזות את הפלט.

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

  • שכחת self: ניסיון לגשת לתכונה או מתודה של אובייקט בתוך מחלקה ללא שימוש ב-self.
  • בלבול בין תכונות מופע לתכונות מחלקה: שימוש שגוי בתכונות מחלקה כאשר הכוונה היא לתכונת מופע ספציפית, או להיפך.
  • שימוש שגוי ב-super(): אי קריאה לקונסטרוקטור של מחלקת האב, או קריאה שגויה למתודות של האב.
  • הבנה לקויה של יחסי "הוא-א" (is-a) מול "יש-לו" (has-a): הורשה מתאימה ליחסי "הוא-א" (לדוגמה, "מרובע הוא-א צורה"). ליחסי "יש-לו" (לדוגמה, "מכונית יש-לה מנוע") עדיף להשתמש בקומפוזיציה (Composition).
  • אי טיפול במקרי קצה: מתודות צריכות להיות חזקות מספיק כדי לטפל בקלטים לא צפויים או במצבים מיוחדים (לדוגמה, מטריצה ריקה, חלוקה באפס).

שאלות לדיון

  • מדוע תכנות מונחה עצמים עדיף על תכנות פרוצדורלי במערכות תוכנה גדולות ומורכבות, כגון מערכת לניהול ספרייה או כלי לדחיסת קבצים?
  • הסבירו את ההבדל בין כימוס להפשטה. כיצד הם משלימים זה את זה בעיצוב מחלקות?
  • תארו תרחיש שבו פולימורפיזם יכול לחסוך לכם כתיבת קוד רב, והדגימו כיצד תממשו זאת ב-Python.
  • תכננו היררכיית מחלקות עבור כלי לניהול חשבונות בנק (לדוגמה: BankAccount, CheckingAccount, SavingsAccount). אילו תכונות ומתודות הייתם מגדירים בכל מחלקה, וכיצד הייתם משתמשים בהורשה ועקיפת מתודות?

נקודות לתשובת מודל

  • OOP מול פרוצדורלי: מודולריות, שימוש חוזר, קלות תחזוקה, ארגון קוד, הפחתת תלות בין רכיבים, קלות הרחבה. דוגמאות ספציפיות כמו הוספת סוגי חשבונות חדשים או אלגוריתמי דחיסה חדשים ללא שינוי קוד קיים.
  • כימוס והפשטה: כימוס הוא מנגנון טכני (איגוד נתונים ומתודות, הסתרת מידע), הפשטה היא עיקרון עיצובי (התמקדות במהות, הסתרת פרטים). כימוס הוא כלי להשגת הפשטה.
  • פולימורפיזם: היכולת להתייחס לאובייקטים מסוגים שונים באמצעות ממשק משותף. דוגמה: רשימה של אובייקטי Shape (עיגול, מלבן) וקריאה למתודת draw() על כל אחד מהם, כאשר כל אובייקט מצייר את עצמו באופן שונה. ב-Python, זה מושג בקלות באמצעות Duck Typing.
  • היררכיית חשבונות:
    • BankAccount (אב): תכונות - account_number, balance. מתודות - deposit(amount), withdraw(amount), get_balance().
    • CheckingAccount (בן): יורש מ-BankAccount. תכונות נוספות - overdraft_limit. עוקף withdraw כדי לבדוק חריגה.
    • SavingsAccount (בן): יורש מ-BankAccount. תכונות נוספות - interest_rate. מתודות נוספות - add_interest(). עשוי לעקוף withdraw למגבלות משיכה.
    • שימוש ב-super().__init__() בקונסטרוקטורים של הבנים.
מצאתם טעות או שחסר משהו?
→ הקודמת
קלט/פלט קבצים וטיפול בשגיאות
הבאה ←
מבני נתונים מורכבים: עצים