פולימורפיזם באמצעות ממשקים
חלק מהיחידה תכנות מונחה עצמים במסלול ה-Dart של Coddy. שיעור 58 מתוך 110.
בשיעור הקודם ראית פולימורפיזם באמצעות ירושה — שימוש בטיפוס של מחלקת אב כדי לעבוד עם אובייקטים של מחלקות צאצא. אבל פולימורפיזם עובד גם באמצעות ממשקים, ולעיתים קרובות הגישה הזאת גמישה יותר.
כאשר מחלקות מממשות את אותו ממשק, אפשר להתייחס אליהן באופן פולימורפי גם אם אין ביניהן קשר של ירושה:
abstract class Printable {
void printDetails();
}
class Invoice implements Printable {
@override
void printDetails() => print('Invoice #1234');
}
class Report implements Printable {
@override
void printDetails() => print('Monthly Report');
}
class Receipt implements Printable {
@override
void printDetails() => print('Receipt for purchase');
}
void printAll(List<Printable> items) {
for (var item in items) {
item.printDetails();
}
}
void main() {
var documents = [Invoice(), Report(), Receipt()];
printAll(documents);
}Invoice, Report ו־Receipt הן מחלקות שאינן קשורות כלל — אין להן מחלקת אב משותפת. ובכל זאת, מכיוון שכולן מממשות את Printable, אפשר לאחסן אותן באותה רשימה ולקרוא ל־printDetails() בכל אחת מהן.
הדבר עוצמתי משום שהוא מאפשר לך להגדיר חוזי התנהגות מבלי לכפות היררכיית ירושה. כל מחלקה יכולה לממש ממשק, בלי קשר למה שהיא יורשת ממנו. הקוד שלך נעשה מודולרי יותר, כי אפשר להוסיף סוגים חדשים שניתנים להדפסה בלי לשנות קוד קיים — פשוט מממשים את הממשק.
אתגר
קלבואו נבנה מערכת נגן מדיה שמדגימה פולימורפיזם באמצעות ממשקים. תיצרו ממשק שמגדיר מה פירוש הדבר להיות "ניתן להפעלה", ואז תממשו כמה סוגי מדיה שאינם קשורים זה לזה, וכולם מקיימים את החוזה הזה — כך שניתן יהיה לטפל בהם באופן אחיד למרות שאין ביניהם קשר של ירושה.
תארגנו את הקוד בשני קבצים:
media.dart: הגדירו כאן את הממשק ואת מחלקות המדיה:- מחלקה מופשטת
Playableעם שתי מתודות מופשטות:play()ו-String getMediaType() - מחלקה
Songשמממשת אתPlayable. צריכים להיות להString titleו-String artist. המתודה שלהplay()מדפיסהPlaying song: [title] by [artist], והמתודהgetMediaType()מחזירה'Audio' - מחלקה
Videoשמממשת אתPlayable. צריכים להיות להString titleו-int duration(בדקות). המתודה שלהplay()מדפיסהPlaying video: [title] ([duration] min), והמתודהgetMediaType()מחזירה'Video' - מחלקה
Podcastשמממשת אתPlayable. צריכים להיות להString titleו-int episode. המתודה שלהplay()מדפיסהPlaying podcast: [title] - Episode [episode], והמתודהgetMediaType()מחזירה'Podcast'
playAll(List<Playable> playlist)שעוברת על הרשימה, ומדפיסה עבור כל פריט את[Media Type]:ואז קוראת למתודהplay()של אותו פריט.- מחלקה מופשטת
main.dart: ייבאו את קובץ המדיה והדגימו פולימורפיזם המבוסס על ממשק:- צרו
List<Playable>שמכילSongעם הכותרת'Imagine'והאמן'John Lennon',Videoעם הכותרת'Dart Tutorial'ומשך של15, ו-Podcastעם הכותרת'Tech Talk'ומספר פרק42 - העבירו את הרשימה הזו אל
playAll()
- צרו
שימו לב של-Song, Video ו-Podcast אין מחלקת אב משותפת — אלה טיפוסים בלתי קשורים לחלוטין. ובכל זאת, מכיוון שכולם מממשים את Playable, אפשר לאחסן אותם באותה רשימה ולטפל בהם באופן אחיד באמצעות הממשק.
פלט צפוי:
Audio:
Playing song: Imagine by John Lennon
Video:
Playing video: Dart Tutorial (15 min)
Podcast:
Playing podcast: Tech Talk - Episode 42נסו בעצמכם
import 'media.dart';
void main() {
// TODO: צרו List<Playable> שמכילה:
// - Song עם הכותרת 'Imagine' והאמן 'John Lennon'
// - Video עם הכותרת 'Dart Tutorial' ומשך של 15
// - Podcast עם הכותרת 'Tech Talk' ופרק 42
// TODO: העבירו את הרשימה ל־playAll()
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות התכנות מונחה העצמים
קבצים חיצונייםספריות וייבואמבוא לתכנות מונחה עצמיםמחלקות לעומת אובייקטיםמילת המפתח thisמתודותמשתני מופעיסודות הבנאיחזרה: מחשבון פשוט4בטיחות מפני ערכי null
מבוא לבטיחות מפני ערכי nullניתן להקצאה ל-null לעומת לא ניתן להקצאה ל-nullהאופרטורים ? ו-!מילת המפתח Late ובטיחות מפני ערכי nullאופרטורים מודעי nullבטיחות מפני ערכי null במחלקותסיכום – מערכת פרופילי משתמשים7מחלקות מופשטות וממשקים
מחלקות מופשטותמתודות מופשטותממשקים ב-Dartממשקים משתמעיםמימוש לעומת הורשהממשקים מרוביםחזרה – מחשבון צורות10אוספים וגנריות
סקירה כללית של List, Set ו-Mapאוספים בטוחים מבחינת טיפוסיםמחלקות גנריותמתודות גנריותאילוצים גנרייםIterable ו-Iteratorסיכום – אחסון גנרי13מושגי OOP מתקדמים
הרכבה לעומת הורשהמתודות הרחבהמחלקות קריאותמחלקות אטומות (Dart 3)רשומות (Dart 3)תבניות והתאמה (3.0)טיפוסים מונים עם מתודות16פרויקט: ניהול ספרייה
סקירת הפרויקטמחלקות ספר ומשתמש2בנאים ב-Dart
בנאי ברירת מחדלבנאים בעלי שםרשימות אתחולבנאים קבועיםבנאי Factoryבנאים מפניםסיכום - בונה צורות5כימוס
חברים ציבוריים לעומת פרטייםמוסכמת הקידומת _פרטיות ברמת הספרייההעמקה ב-getters וב-settersהסתרת מידעסיכום – רשומות תלמידים8מיקסינים
מבוא למיקסיניםיצירת מיקסיניםשימוש במספר מיקסיניםמילת המפתח on במיקסיניםמיקסינים לעומת ירושהמיקסינים לעומת ממשקסיכום – מערכת בעלי החיים3מאפייני מחלקה
איברי מופע לעומת איברים סטטייםשדות final ו-constמשתני lateמתודות ושדות סטטייםGetters ו-Settersסיכום – מנהל חשבונות בנק6ירושה
ירושה בסיסיתמילת המפתח superדריסת מתודותהאנוטציה @overrideמילת המפתח final למחלקהבנאים וירושהסיכום – היררכיית עובדים9פולימורפיזם
יסודות הפולימורפיזםפולימורפיזם באמצעות ממשקיםבדיקת טיפוסים בזמן ריצההאופרטורים is ו-asמילת המפתח קווריאנטיסיכום — מעבד תשלומים12תכנות מונחה עצמים אסינכרוני
Future-ים ו-async/awaitיסודות ה-Streamsבקרי Streamsבנאים אסינכרונייםאסינכרוניות במתודות של מחלקהסיכום - אחזור נתוניםתרגלו בעצמכם: קומפיילר Dart אונליין