Menu
Coddy logo textTech

ממשק לעומת מחלקה מופשטת

חלק מהיחידה תכנות מונחה עצמים במסלול ה-PHP של Coddy. שיעור 30 מתוך 91.

עכשיו, לאחר שלמדת על ממשקים ועל מחלקות מופשטות, נבהיר מתי להשתמש בכל אחד מהם. הם עשויים להיראות דומים, אך הם משמשים למטרות שונות ובעלי יכולות ייחודיות.

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

השתמשו בממשק כשרוצים להגדיר חוזה שמחלקות שאינן קשורות זו לזו יכולות לממש. לדוגמה, גם Printer וגם Logger עשויות לממש ממשק Writable, אף שאין להן אב משותף.

השתמשו במחלקה מופשטת כשיש לכם מחלקות קשורות שחולקות קוד משותף. אם גם המחלקות Dog וגם Cat צריכות את אותה מימוש של המתודה eat(), מחלקת Animal מופשטת מאפשרת לכם לכתוב את הקוד הזה פעם אחת.

אפשר גם לשלב בין שתי הגישות. מחלקה יכולה לרשת ממחלקה מופשטת ובו בזמן לממש כמה ממשקים:

<?php
abstract class Animal {
    protected $name;
    
    public function eat() {
        return $this->name . " is eating";
    }
}

interface Swimmable {
    public function swim();
}

class Duck extends Animal implements Swimmable {
    public function __construct($name) {
        $this->name = $name;
    }
    
    public function swim() {
        return $this->name . " is swimming";
    }
}

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

challenge icon

אתגר

קל

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

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

ארגנו את הקוד שלכם בארבעה קבצים:

  • Refuelable.php: הגדירו ממשק Refuelable עם חתימת מתודה יחידה: refuel($amount). יכולת זו יכולה להתאים לכל מחלקה שזקוקה לתדלוק, ללא קשר להיררכיית הירושה שלה.
  • Vehicle.php: הגדירו מחלקה מופשטת Vehicle שמספקת פונקציונליות משותפת לכל כלי הרכב. צריכה להיות לה תכונה מוגנת $brand ותכונה מוגנת $fuelLevel (שמתחילה ב-0). הבנאי מקבל את שם המותג. כללו מתודה קונקרטית getBrand() שמחזירה את המותג, מתודה קונקרטית getFuelLevel() שמחזירה את רמת הדלק הנוכחית, ומתודה מופשטת drive() שמחלקות הצאצא חייבות לממש.
  • Car.php: צרו מחלקה Car שמרחיבה את Vehicle ומממשת את Refuelable. כללו את שני הקבצים הנדרשים בראש הקובץ. הבנאי מקבל את המותג ומעביר אותו לבנאי של מחלקת האב. ממשו את drive() כך שתחזיר "[brand] car is driving". ממשו את refuel($amount) כך שתוסיף את הכמות לרמת הדלק ותחזיר "[brand] refueled to [fuelLevel] liters".
  • main.php: כללו את קובץ Car. תקבלו שתי קלטים: שם מותג וכמות דלק (המירו למספר שלם). צרו Car עם המותג. הדפיסו את התוצאה של drive() בשורה הראשונה, ואז הדפיסו בשורה השנייה את התוצאה של refuel() עם כמות הדלק.

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

נסו בעצמכם

<?php
require_once 'Car.php';

// קרא את הקלט
$brand = trim(fgets(STDIN));
$fuelAmount = intval(trim(fgets(STDIN)));

// TODO: צור Car עם המותג

// TODO: הדפס את התוצאה של drive() בשורה הראשונה

// TODO: הדפס את התוצאה של refuel() עם כמות הדלק בשורה השנייה
?>
quiz iconבחנו את עצמכם

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

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר PHP אונליין