תבנית המרוכב
חלק מהיחידה תכנות מונחה עצמים במסלול ה-Dart של Coddy. שיעור 99 מתוך 110.
תבנית Composite מאפשרת להתייחס באופן אחיד לאובייקטים בודדים ולקבוצות של אובייקטים. היא מרכיבה אובייקטים למבני עץ שבהם גם לרכיבים בודדים וגם לאוספי רכיבים יש אותו ממשק. התבנית מתאימה במיוחד לייצוג היררכיות כמו מערכות קבצים, תרשימים ארגוניים או רכיבי ממשק משתמש.
לתבנית יש שני סוגי משתתפים: צומתי עלה (אובייקטים יחידים ללא ילדים) וצומתי מורכב (מכלים שמכילים רכיבים אחרים). שניהם מממשים ממשק רכיב משותף:
abstract class FileSystemItem {
String get name;
int getSize();
void display([String indent = '']);
}
class File implements FileSystemItem {
@override
final String name;
final int size;
File(this.name, this.size);
@override
int getSize() => size;
@override
void display([String indent = '']) {
print('$indent- $name ($size KB)');
}
}
class Folder implements FileSystemItem {
@override
final String name;
final List<FileSystemItem> _children = [];
Folder(this.name);
void add(FileSystemItem item) => _children.add(item);
@override
int getSize() => _children.fold(0, (sum, item) => sum + item.getSize());
@override
void display([String indent = '']) {
print('$indent+ $name/');
for (var child in _children) {
child.display('$indent ');
}
}
}
void main() {
var docs = Folder('Documents');
docs.add(File('resume.pdf', 150));
docs.add(File('photo.jpg', 2400));
var projects = Folder('Projects');
projects.add(File('main.dart', 25));
docs.add(projects);
docs.display();
print('Total: ${docs.getSize()} KB');
}המחלקה Folder יכולה להכיל גם אובייקטים מסוג File וגם אובייקטים אחרים מסוג Folder. כשקוראים ל־getSize() על תיקייה, היא מחשבת באופן רקורסיבי את הגודל הכולל של כל התוכן שלה. קוד הלקוח לא צריך לדעת אם הוא עובד עם קובץ יחיד או עם היררכיה שלמה של תיקיות — שניהם מגיבים לאותן שיטות.
אתגר
קלבואו נבנה מערכת תרשים ארגוני באמצעות דפוס Composite! תיצרו מבנה שבו ניתן להתייחס באופן אחיד הן לעובדים יחידים והן למחלקות (המכילות עובדים ומחלקות אחרות) — מושלם לייצוג היררכיות של חברות.
תארגנו את הקוד שלכם בשני קבצים:
organization.dart: הקובץ הזה מכיל את ממשק הרכיב שלכם ואת מחלקות העלה והמורכבת. צרו מחלקה מופשטתOrganizationUnitעם getter בשםname, שיטה בשםgetSalaryBudget()שמחזירהint, ושיטה בשםdisplay([String indent = ''])להצגת ההיררכיה. בנו מחלקה בשםEmployee(העלה), שמממשת אתOrganizationUnit. צריכים להיות לה שם ומשכורת, כאשרgetSalaryBudget()מחזירה את המשכורת של העובד. השיטהdisplay()שלה צריכה להדפיס[indent]- [name] ($[salary]). לאחר מכן, צרו מחלקה בשםDepartment(המורכבת), שגם היא מממשת אתOrganizationUnit. צריכים להיות לה שם ורשימה של צאצאים מסוגOrganizationUnit. הוסיפו שיטה בשםadd()כדי להוסיף עובדים או תת-מחלקות. השיטהgetSalaryBudget()שלה צריכה לסכם באופן רקורסיבי את התקציבים של כל הצאצאים. השיטהdisplay()שלה צריכה להדפיס[indent]+ [name]/ואז להציג כל צאצא עם הזחה גדולה יותר (הוסיפו שני רווחים).main.dart: ייבאו את קובץ הארגון שלכם ובנו מבנה של חברה. צרו מחלקתEngineeringשמכילה שני עובדים:Aliceעם משכורת80000ו-Bobעם משכורת75000. צרו מחלקתQAעם עובד אחד:Carolעם משכורת65000. כעת צרו מחלקתTechnologyוהוסיפו אתEngineeringואתQAכתת-מחלקות שלה. קראו ל-display()במחלקת Technology, ואז הדפיסוTotal Budget: $ואחריו את תקציב המשכורות הכולל.
היופי בדפוס Composite הוא ש-Technology.getSalaryBudget() מחשבת באופן אוטומטי את הסכום הכולל של כל המחלקות והעובדים המקוננים — קוד הלקוח לא צריך להכיר את המבנה הפנימי!
הפלט הצפוי:
+ Technology/
+ Engineering/
- Alice ($80000)
- Bob ($75000)
+ QA/
- Carol ($65000)
Total Budget: $220000נסו בעצמכם
import 'organization.dart';
void main() {
// TODO: צור מחלקת Engineering
// TODO: הוסף את Alice עם שכר של 80000
// TODO: הוסף את Bob עם שכר של 75000
// TODO: צור מחלקת QA
// TODO: הוסף את Carol עם שכר של 65000
// TODO: צור מחלקת Technology
// TODO: הוסף את Engineering ואת QA כתת־מחלקות
// TODO: קרא ל־display() על מחלקת Technology
// TODO: הדפס את "Total Budget: $" ואחריו את תקציב השכר הכולל
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
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בנאים אסינכרונייםאסינכרוניות במתודות של מחלקהסיכום - אחזור נתונים15תבניות עיצוב חלק 2
תבנית הפקודהתבנית המתאםתבנית העיצובןתבנית שיטת התבניתתבנית המצבתבנית המרוכבתבנית המאגרתרגלו בעצמכם: קומפיילר Dart אונליין