Menu
Coddy logo textTech

תבנית Factory

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

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

תבנית זו שימושית במיוחד כשיש לך כמה מחלקות קשורות שחולקות ממשק משותף, ואתה רוצה להחליט איזו מהן ליצור בהתאם לתנאי מסוים. נבחן מערכת התראות שיכולה לשלוח הודעות בערוצים שונים:

<?php
interface Notification {
    public function send(string $message): string;
}

class EmailNotification implements Notification {
    public function send(string $message): string {
        return "Email: $message";
    }
}

class SmsNotification implements Notification {
    public function send(string $message): string {
        return "SMS: $message";
    }
}

בלי מפעל, היית מפזר הצהרות if וקריאות new בכל מקום. המפעל מרכז את הלוגיקה הזאת:

<?php
class NotificationFactory {
    public static function create(string $type): Notification {
        return match($type) {
            'email' => new EmailNotification(),
            'sms' => new SmsNotification(),
            default => throw new InvalidArgumentException("Unknown type: $type")
        };
    }
}

$notification = NotificationFactory::create('email');
echo $notification->send('Hello!');

פלט:

Email: Hello!

היתרון המרכזי הוא שהקוד שלך תלוי בממשק Notification, ולא במחלקות קונקרטיות. אם בהמשך תוסיף מחלקה בשם PushNotification, תצטרך לעדכן רק את המפעל. כל הקוד שמשתמש במפעל יקבל אוטומטית גישה לסוג החדש, ללא שינויים.

challenge icon

אתגר

קל

נבנה מערכת ליצירת מסמכים באמצעות תבנית Factory. סוגי מסמכים שונים (PDF, HTML, טקסט פשוט) חולקים ממשק משותף, אך מפיקים פלטים שונים: זהו תרחיש מושלם לריכוז יצירת האובייקטים במפעל.

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

  • Document.php: צרו ממשק Document שמגדיר את החוזה שכל סוגי המסמכים חייבים לקיים. צריכה להיות בו מתודה יחידה render(string $content): string שמקבלת תוכן ומחזירה את פלט המסמך המעוצב.
  • Documents.php: כללו את ממשק Document וצרו שלוש מחלקות שמממשות אותו:
    • PdfDocument: המתודה render() שלה מחזירה "PDF: [content]"
    • HtmlDocument: המתודה render() שלה מחזירה "<html>[content]</html>"
    • TextDocument: המתודה render() שלה מחזירה "TXT: [content]"
  • DocumentFactory.php: כללו את קובץ Documents וצרו מחלקת DocumentFactory עם מתודה סטטית create(string $type): Document. המתודה צריכה להשתמש ב-match כדי להחזיר את אובייקט המסמך המתאים לפי הסוג:
    • "pdf" מחזיר אובייקט חדש של PdfDocument
    • "html" מחזיר אובייקט חדש של HtmlDocument
    • "text" מחזיר אובייקט חדש של TextDocument
    • כל סוג אחר צריך לגרום לזריקת InvalidArgumentException עם ההודעה "Unknown document type: [type]"
  • main.php: כללו את קובץ DocumentFactory. תקבלו שתי קלטים: סוג מסמך והתוכן לעיבוד.

    השתמשו במפעל כדי ליצור את סוג המסמך המתאים, ואז קראו למתודה render() שלו עם התוכן והדפיסו את התוצאה.

    בשורה חדשה, הדפיסו "Factory benefit: Adding new types only requires updating the factory" כדי להדגיש מדוע התבנית הזו שימושית.

תבנית Factory משאירה את הקוד שלכם גמיש: כשתצטרכו להוסיף בהמשך MarkdownDocument, תצטרכו לעדכן רק את המפעל, בעוד שכל הקוד הקיים ימשיך לעבוד ללא שינוי.

נסו בעצמכם

<?php
require_once 'DocumentFactory.php';

// קרא את הקלט
$type = trim(fgets(STDIN));
$content = trim(fgets(STDIN));

// TODO: השתמש ב-DocumentFactory כדי ליצור את סוג המסמך המתאים
// TODO: קרא למתודה render() עם התוכן והדפס את התוצאה
// TODO: בשורה חדשה, הדפס "Factory benefit: Adding new types only requires updating the factory"

?>
quiz iconבחנו את עצמכם

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

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

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