Menu
Coddy logo textTech

תבנית המרוכב

חלק מהיחידה תכנות מונחה עצמים במסלול ה-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() על תיקייה, היא מחשבת באופן רקורסיבי את הגודל הכולל של כל התוכן שלה. קוד הלקוח לא צריך לדעת אם הוא עובד עם קובץ יחיד או עם היררכיה שלמה של תיקיות — שניהם מגיבים לאותן שיטות.

challenge icon

אתגר

קל

בואו נבנה מערכת תרשים ארגוני באמצעות דפוס 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: $" ואחריו את תקציב השכר הכולל
}
quiz iconבחנו את עצמכם

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

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

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