דילוג לתוכן המרכזי
מודול 3 · שיעור 2 מתוך 26/14 בקורס~15 min
שיעורי מודול (2/2)

פולימורפיזם ושיעורים מופשטים

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

פולימורפיזם

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

Java
class Animal {
    public void makeSound() {
        System.out.println("Verso...");
    }
}

class Dog extends Animal {
    public void makeSound() {
        System.out.println("Woof");
    }
}

class Cat extends Animal {
    public void makeSound() {
        System.out.println("Miao");
    }
}

הודות לפולימורפיזם, אנו יכולים לעשות זאת:

Java
Animal myAnimal1 = new Dog(); // Polymorphism
Animal myAnimal2 = new Cat(); // Polymorphism

myAnimal1.makeSound(); // Executes Dog's method (Woof)
myAnimal2.makeSound(); // Executes Cat's method (Miao)

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

שיעורים מופשטים (abstract)

מחלקה מופשטת היא מחלקה המסומנת במילת המפתח abstract שלא ניתן להפעיל ישירות (לא ניתן לבצע new MyAbstractClass()). הוא משמש כ"תבנית חלקית" לשיעורים אחרים.

שיטות מופשטות

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

Java
abstract class Shape {
    String color;

    // Abstract method (no body)
    public abstract double getArea();
}

class Circle extends Shape {
    double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    // Required to implement getArea
    @Override
    public double getArea() {
        return Math.PI * radius * radius;
    }
}

כריכה דינמית / כריכה מאוחרת

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

שיעורים מופשטים ויישום חסר

אם תת-מחלקה יורשת ממחלקה מופשטת, יש לה שתי אפשרויות:

  1. הטמיע את כל השיטות המופשטות: במקרה זה, תת המחלקה יכולה להיות מחלקה רגילה (קונקרטית) וניתנת לאינסטציה.
  2. הכרז על עצמה אבסטרקטית: אם תת-המחלקה אינה מספקת מימוש לכל שיטות האבסטרקט שעברו בירושה, יש להכריז עליה גם עם מילת המפתח abstract.
Java
abstract class Animal {
    public abstract void makeSound();
}

// This class MUST be abstract because it does not implement makeSound()
abstract class Canine extends Animal {
    // Inherits makeSound() but does not implement it
}

נסה זאת בעצמך

פעילות גופנית#java.m3.l2.e1
ניסיונות: 0טוען...

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

טוען עורך...
הצג רמז

כתוב `Shape s = new Circle();` כדי להשתמש בסוג הבסיס כסוג ההפניה.

הפתרון זמין לאחר 3 ניסיונות

פעילות גופנית#java.m3.l2.e2
ניסיונות: 0טוען...

הפוך את המחלקה Shape למופשטת והוסף את השיטה המופשטת double getArea(). לאחר מכן השלימו את ריבוע כך שירחיב את Shape ויישם את getArea() חוזר צד * צד.

טוען עורך...
הצג רמז

הכריז על 'תקציר ציבורי כפול getArea();' ב-Shape. בכיכר, הוסף `@Override public double getArea() { return side * side; }`.

הפתרון זמין לאחר 3 ניסיונות

פעילות גופנית#java.m3.l2.e3
ניסיונות: 0טוען...

הכריז בשיטה הראשית על מערך מסוג Shape[] המכיל אובייקט Circle עם רדיוס 2.0 ואובייקט Square עם צלע 3.0. לאחר מכן, השתמש בלולאה (עבור או עבור כל אחד) כדי להדפיס את השטח של כל צורה על ידי הפעלת השיטה getArea()‎.

טוען עורך...
הצג רמז

הכריז על המערך עם צורות `Shape[] = { new Circle(2.0), new Square(3.0) };` ולעוף דרכו באמצעות `for (Shape s : shapes)` הדפסת `s.getArea()`.

הפתרון זמין לאחר 3 ניסיונות