תבנית המורכב
חלק מהיחידה תכנות מונחה עצמים במסלול ה-PHP של Coddy. שיעור 80 מתוך 91.
תבנית Composite היא תבנית עיצוב מבנית שמאפשרת לך להרכיב אובייקטים למבני עץ ולעבוד איתם כאילו היו אובייקטים בודדים. היא מושלמת לייצוג היררכיות של חלק ושלם, שבהן רוצים להתייחס לאובייקטים בודדים ולקבוצות של אובייקטים באופן אחיד.
חשבו על מערכת קבצים. תיקייה יכולה להכיל קבצים ותיקיות אחרות.
כשמחשבים את הגודל הכולל, רוצים לקרוא לאותה שיטה גם בקבצים וגם בתיקיות, והתיקיות אמורות לסכם באופן רקורסיבי את התוכן שלהן. תבנית ה־Composite מאפשרת לעשות זאת בצורה חלקה, בכך שהיא מספקת גם לעלים (קבצים) וגם למורכבים (תיקיות) את אותו ממשק.
<?php
interface FileSystemItem {
public function getName(): string;
public function getSize(): int;
}
class File implements FileSystemItem {
public function __construct(
private string $name,
private int $size
) {}
public function getName(): string {
return $this->name;
}
public function getSize(): int {
return $this->size;
}
}
class Folder implements FileSystemItem {
private array $items = [];
public function __construct(private string $name) {}
public function getName(): string {
return $this->name;
}
public function add(FileSystemItem $item): void {
$this->items[] = $item;
}
public function getSize(): int {
$total = 0;
foreach ($this->items as $item) {
$total += $item->getSize();
}
return $total;
}
}
עכשיו אפשר לבנות מבני עץ ולהתייחס אליהם באופן אחיד:
<?php
$docs = new Folder("Documents");
$docs->add(new File("resume.pdf", 250));
$docs->add(new File("cover.docx", 50));
$images = new Folder("Images");
$images->add(new File("photo.jpg", 1500));
$root = new Folder("Root");
$root->add($docs);
$root->add($images);
$root->add(new File("readme.txt", 10));
echo $root->getSize();
פלט:
1810קוד הלקוח קורא ל־getSize() בלי להתחשב בשאלה אם הוא מטפל בקובץ יחיד או במבנה תיקיות מקונן עמוק. התבנית מטפלת ברקורסיה באופן פנימי, וכך קל לעבוד עם היררכיות מורכבות.
אתגר
קלבואו נבנה מערכת תרשים ארגוני באמצעות תבנית Composite. לחברות יש מבנה היררכי שבו מחלקות יכולות להכיל עובדים ותת־מחלקות אחרות: מבנה עץ מושלם שבו רוצים לחשב סכומים באופן אחיד בכל רחבי הארגון.
תארגנו את הקוד שלכם בארבעה קבצים:
OrganizationUnit.php: הגדירו ממשקOrganizationUnitשגם עובדים יחידים וגם מחלקות יממשו. צריכות להיות לו שתי שיטות:getName(): stringו-getSalary(): int. הממשק המשותף הזה מאפשר להתייחס באותו אופן לעובדים יחידים ולמחלקות שלמות בעת חישוב העלויות.Employee.php: כללו את הממשק OrganizationUnit וצרו מחלקתEmployeeשמממשת אותו. עובד הוא צומת עלה בעץ הארגוני שלכם. יש לו שם ושכר, אך הוא אינו יכול להכיל יחידות אחרות. השתמשו בקידום מאפיינים בבנאי כדי לקבל את השם והשכר, וממשו את שתי שיטות הממשק.Department.php: כללו את הממשק OrganizationUnit וצרו מחלקתDepartmentשמממשת אותו. מחלקה היא אובייקט מורכב שיכול להכיל עובדים וגם מחלקות אחרות. המחלקה שלכם צריכה:- לקבל שם בבנאי שלה
- לממש את
getName()כדי להחזיר את שם המחלקה - להכיל שיטה
add(OrganizationUnit $unit): voidלהוספת עובדים או תת־מחלקות - לממש את
getSalary()כדי להחזיר את השכר הכולל של כל היחידות שהיא מכילה (על ידי חיבור רקורסיבי של כל מה שנמצא בתוכה)
main.php: כללו את הקבצים Employee ו-Department. תקבלו קלט אחד: מחרוזת JSON שמייצגת את מבנה הארגון.ה-JSON יהיה בפורמט הזה:
{"Engineering": [{"name": "Alice", "salary": 80000}, {"name": "Bob", "salary": 75000}], "Sales": [{"name": "Carol", "salary": 65000}]}כל מפתח הוא שם של מחלקה, והערך שלו הוא מערך של עובדים עם שמותיהם ומשכורותיהם.
צרו מחלקת שורש
Departmentבשם"Company". עבור כל מחלקה ב-JSON, צרו אובייקטDepartment, הוסיפו אליו את העובדים שלה, ואז הוסיפו את המחלקה לחברה. לבסוף, הדפיסו את השכר הכולל של החברה בפורמט הזה:Total Salary: [amount]
היופי בתבנית Composite הוא שקריאה ל-getSalary() במחלקת החברה מחשבת אוטומטית את הסכום של כל המחלקות והעובדים המקוננים: קוד הלקוח אינו צריך להכיר את המבנה הפנימי.
נסו בעצמכם
<?php
require_once 'Employee.php';
require_once 'Department.php';
// קרא את קלט ה-JSON
$input = trim(fgets(STDIN));
$data = (array)json_decode($input, true);
// TODO: צור Department ראשית בשם "Company"
// TODO: עבור על כל מחלקה בנתוני ה-JSON
// עבור כל מחלקה:
// - צור אובייקט Department חדש
// - הוסף כל עובד למחלקה הזו
// - הוסף את המחלקה ל-Company
// TODO: הדפס את השכר הכולל בפורמט: Total Salary: [amount]
?>השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות התכנות מונחה העצמים (OOP)
קבצים חיצונייםמבוא ל-OOPמחלקות לעומת אובייקטיםמילת המפתח $thisמתודותמאפייניםבנאי (__construct)הורס (__destruct)חזרה: מחשבון פשוט4ירושה
ירושה בסיסיתמילת המפתח parent::דריסת מתודותמילת המפתח finalמחלקות מופשטותסיכום – היררכיית עובדים7כימוס
ציבורי, מוגן, פרטימפרטי גישה לעומקמתודות גישה ועדכוןהסתרת מידעקידום פרמטרים בבנאי (8.0)סיכום – מערכת רישומי תלמידים10מושגי OOP מתקדמים
הרכבה לעומת ירושההזרקת תלויותמחלקות אנונימיותטיפוסי Enum (PHP 8.1)סיבים (PHP 8.1)העמקה בשכפול אובייקטיםמחוללים ואיטרטורים13תבניות עיצוב חלק 2
תבנית הפקודהתבנית המתאםתבנית העיצובןתבנית שיטת התבניתתבנית המצבתבנית המורכבתבנית המאגר2מרחבי שמות וטעינה אוטומטית
מבוא למרחבי שמותמילת המפתח useתקן הטעינה האוטומטית PSR-4הטוען האוטומטי של Composerסיכום – פרויקט מאורגן5ממשקים וחוזים
מבוא לממשקיםמימוש ממשקיםמימוש של כמה ממשקיםממשק לעומת מחלקה מופשטתרמזי טיפוסים עם ממשקיםסיכום - מחשבון צורות8מתודות קסם
מבוא למתודות קסם__toString ו־__debugInfo__get, __set, __isset, __unset__call ו־__callStatic__clone ושיבוט אובייקטים__serialize ו־__unserializeסיכום – אוסף מותאם אישית3מאפייני מחלקה
מאפייני מופע לעומת מאפיינים סטטייםקבועים במחלקותמתודות ומאפיינים סטטייםמאפיינים פרטיים ומוגניםמאפיינים לקריאה בלבד (PHP 8.1)סיכום – מנהל חשבון בנק6פולימורפיזם
בחינה מחדש של דריסת מתודותפולימורפיזם באמצעות ממשקיםרמזי טיפוסים וטיפוסי איחודקישור סטטי מאוחרסיכום — מעבד תשלומיםתרגלו בעצמכם: קומפיילר PHP אונליין