Smart-World Surf

יחידה 6: פולימורפיזם וממשקים

הבנת עקרון הפולימורפיזם ושימוש בממשקים ומחלקות אבסטרקטיות.

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

פולימורפיזם – העיקרון המרכזי

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

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

סוגי פולימורפיזם עיקריים ב-Java:

  • פולימורפיזם בזמן הידור (Compile-time Polymorphism / Overloading): מתייחס למצב שבו ישנן מספר שיטות בעלות אותו שם אך עם חתימות שונות (מספר או סוג פרמטרים שונים) באותה מחלקה. המהדר קובע איזו שיטה לקרוא על בסיס הפרמטרים המועברים.
  • פולימורפיזם בזמן ריצה (Runtime Polymorphism / Overriding): מתרחש כאשר מחלקת בת (subclass) מספקת מימוש ספציפי לשיטה שכבר קיימת במחלקת האב (superclass). בזמן ריצה, ה-JVM קובע איזו גרסה של השיטה לקרוא, על בסיס סוג האובייקט בפועל, ולא על בסיס סוג ההפניה. זהו הסוג העיקרי אליו מתייחסים לרוב כשמדברים על פולימורפיזם ב-OOP.

ממשקים (Interfaces)

ממשק ב-Java הוא חוזה המגדיר סט של שיטות שכל מחלקה המממשת אותו חייבת לספק להן מימוש. הוא מאפשר להגדיר התנהגות משותפת למחלקות שאינן בהכרח קשורות בהיררכיית ירושה ישירה.

ממשק (Interface): סוג של "חוזה" ב-Java המכיל חתימות של שיטות (לפני Java 8, רק אבסטרקטיות), קבועים (final static) ושיטות default/static (החל מ-Java 8). מחלקה המממשת ממשק חייבת לספק מימוש לכל השיטות האבסטרקטיות שהוגדרו בו.

מאפייני ממשקים:

  • הגדרת חוזה: ממשקים מגדירים "מה" אובייקט יכול לעשות, מבלי לפרט "איך" הוא עושה זאת.
  • ירושה מרובה של סוג (Multiple Inheritance of Type): מחלקה יכולה לממש מספר ממשקים, ובכך לרשת התנהגויות מכמה "אבות" שונים.
  • שיטות אבסטרקטיות: עד Java 8, כל השיטות בממשק היו אבסטרקטיות באופן מרומז (implicit). החל מ-Java 8, ניתן להוסיף שיטות default ו-static עם מימוש.
  • קבועים: כל השדות בממשק הם public static final באופן מרומז.

מחלקות אבסטרקטיות (Abstract Classes)

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

מחלקה אבסטרקטית (Abstract Class): מחלקה שאינה ניתנת ליצירת מופע ישיר (instantiation). היא יכולה להכיל גם שיטות ממומשות (concrete methods) וגם שיטות אבסטרקטיות (ללא מימוש), וכן שדות. היא משמשת כבסיס משותף למחלקות קשורות.

מאפייני מחלקות אבסטרקטיות:

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

פולימורפיזם בפעולה: יתרונות ושימושים

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

יתרונות מרכזיים:

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

השוואה: ממשקים מול מחלקות אבסטרקטיות

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

ממשק (Interface)

  • ירושה: מאפשר ירושה מרובה של סוג (מחלקה יכולה לממש מספר ממשקים).
  • מימוש: עד Java 8, רק שיטות אבסטרקטיות (ללא מימוש). מ-Java 8, ניתן להוסיף שיטות default ו-static עם מימוש.
  • שדות: רק קבועים (public static final).
  • בנאים: אין בנאים.
  • מטרה: הגדרת חוזה התנהגותי (מה אובייקט יכול לעשות) למחלקות לא קשורות.

מחלקה אבסטרקטית (Abstract Class)

  • ירושה: מאפשרת ירושה יחידה (מחלקה יכולה לרשת רק ממחלקת אב אחת).
  • מימוש: יכולה להכיל שיטות אבסטרקטיות (ללא מימוש) וגם שיטות ממומשות (concrete methods).
  • שדות: יכולה להכיל שדות רגילים (משתנים) בנוסף לקבועים.
  • בנאים: יכולה להכיל בנאים (נקראים ע"י מחלקות הבת).
  • מטרה: הגדרת בסיס משותף (מה אובייקט "הוא") למחלקות קשורות בהיררכיה, עם מימוש חלקי.

שאלות לדיון

  • הסבר כיצד פולימורפיזם בזמן ריצה תורם לגמישות וליכולת הרחבה של מערכת תוכנה. תן דוגמה קצרה ב-Java.
  • מהו ההבדל המהותי בין שימוש בממשק לבין שימוש במחלקה אבסטרקטית? באילו מצבים תבחר בכל אחד מהם?
  • כיצד שיטות default בממשקים (החל מ-Java 8) משנות את תפקידם המסורתי של ממשקים?
  • האם ניתן ליצור מופע (instance) של מחלקה אבסטרקטית? ושל ממשק? הסבר מדוע.

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

לשאלה: "מהו ההבדל המהותי בין שימוש בממשק לבין שימוש במחלקה אבסטרקטית? באילו מצבים תבחר בכל אחד מהם?"

  • ממשק: מגדיר "חוזה" התנהגותי (מה אובייקט יכול לעשות). מתאים למצבים שבהם רוצים להגדיר יכולת או התנהגות משותפת למחלקות שאינן קשורות בהיררכיית ירושה, או כאשר נדרשת "ירושה מרובה" של יכולות. דוגמאות: Comparable, Runnable.
  • מחלקה אבסטרקטית: מגדירה "בסיס" למחלקות קשורות בהיררכיית ירושה (מה אובייקט "הוא"). מתאימה למצבים שבהם יש מימוש חלקי משותף למחלקות הבת, או כאשר רוצים לספק מימוש ברירת מחדל לחלק מהשיטות, יחד עם דרישה לממש שיטות ספציפיות. דוגמאות: AbstractList, AbstractMap.
  • הבדלים טכניים: ירושה מרובה (ממשק כן, מחלקה אבסטרקטית לא), יכולת להכיל שדות ושיטות ממומשות (מחלקה אבסטרקטית כן, ממשק רק קבועים ושיטות default/static), בנאים (מחלקה אבסטרקטית כן, ממשק לא).
  • בחירה: בחר בממשק כאשר אתה רוצה להגדיר יכולת שכל מחלקה יכולה "לרכוש", ללא קשר למקומה בהיררכיה. בחר במחלקה אבסטרקטית כאשר יש לך קבוצה של מחלקות קשורות שחולקות מימוש משותף כלשהו, אך גם דורשות מימוש ספציפי משלהן לחלק מהשיטות.
מצאתם טעות או שחסר משהו?
→ הקודמת
ירושה
הבאה ←
רקורסיה