תבנית עיצוב Singleton

הסבר עם דוגמאות ב-PHP לתבנית העיצוב Singleton ולמה היא כל כך חשובה.

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

אז מה זה Singleton? זו תבנית עיצוב שמגבילה את מספר ה-instances שאפשר לעשות ל-class שלה. לכמה? לאחד. מה ההגיון בהגבלה הזו? הרי כל הרעיון מאחורי אובייקטים הוא שנוכל לעשות להם instances כרצוננו! למרות זאת יש מקרים שאם נעשה יותר מ-instance אחד נשחוק את משאבי המערכת ולפעמים גם לא צריך לעשות יותר מ-instance אחד. הדוגמה הקלאסית היא התחברות למסד נתונים – צריך רק חיבור אחד בכל פעם, כי כמה חיבורים פשוט ישביתו את האפליקציה. גם לא צריך יותר מחיבור אחד בכל זמן ריצה, לפיכך כדאי לנו להגביל את כמות ה-instances לאחד.

אולי זה יהיה ברור יותר עם דוגמה.


class Database 
{ 
    public function __construct() { ... } 
    public function connect() { ... } 
    public function query() { ... } 
    ... 
}  

הקוד שלעיל הוא קוד קצת אבסטרקטי של קלאס שמדמה חיבור למסד נתונים. כאמור, אנחנו לא רוצים שיעשו לו instance יותר מפעם אחת. איך אני עושה את זה? ראשית אני מגדיר תכונה שתכיל את ה-instance שלי.


class Database 
{ 
    // Store the single instance of Database 
    private static $m_pInstance; 

    ...     
}  

שימו לב שהיא חייבת להיות סטטית.

עכשיו, וזה הקטע המוזר, אנחנו הופכים את הקונסטרקטור למתודה פרטית. רגע, מה? למה פרטית? זה אחד הדברים בתבנית Singleton שקשים לתפיסה. הסיבה שהקונסטרקטור הופך לפרטי היא שאי אפשר יהיה להפעיל אותו 'מבחוץ' וכך אי אפשר יהיה לעשות instance מבחוץ:


class Database 
{ 
    // Store the single instance of Database 
    private static $m_pInstance; 

    private function __construct() { ... } 
}  

על מנת שבכל זאת נוכל להפעיל את ה-class הזה, אנחנו צריכים ליצור מתודה פומבית שהיא זו שתקרא לקונסטרקטור:


public static function getInstance() 
{ 
    if (!self::$m_pInstance) 
    { 
        self::$m_pInstance = new Database(); 
    } 

    return self::$m_pInstance; 
}  

מה המתודה הזו עושה? היא בודקת שהמשתנה הסטטי שיצרנו קודם מלא או ריק. במידה והוא ריק, היא יוצרת instance ל-class באמצעות הקונסטרקטור ומכניסה רפרנס למשתנה הסטטי שיצרנו קודם. במידה והוא מלא, היא פשוט מחזירה את הרפרנס. זה הכל.

לפיכך, אם אנו משתמשים בתבנית עיצוב Singleton, אנחנו נעשה instance לקלאס שלנו באופן הבא:


$pDatabase = Database::getInstance(); 
$aResult = $pDatabase->query('...');  

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


$pDatabase = new Database(); 
$aResult = $pDatabase->query('...');  

כך בעצם, על ידי שימוש נבון במשתנה סטטי ובכימוס של קונסטרקטור, אנחנו מונעים מסקריפט PHP לעשות יותר מ-instance אחד לקלאס מסוים ועדיין להנות מיכולת גישה אל האובייקט שנוצר באמצעות הקלאס הזה. אם אתם כותבים אפליקציה שקוראת למסד נתונים, כדאי מאד שתשתמשו ב-Singleton לבצע את הקריאות למסד הנתונים בכל פעם שאתם צריכים לעשות קריאה כזו. כך תמנעו מבעיות פוטנציאליות של העמסה רצינית על מסד הנתונים ועל השרת שלכם.

אז בסופו של דבר, הטינה שלי כלפי Singleton לא היתה מוצדקת.

פוסטים נוספים שכדאי לקרוא

DALL·E 2023-10-21 22.28.58 - Photo of a computer server room with red warning lights flashing, indicating a potential cyber threat. Multiple screens display graphs showing a sudde
יסודות בתכנות

מבוא לאבטחת מידע: IDOR

הסבר על התקפה אהובה ומוצלחת שבאמצעותה שואבים מידע מאתרים

גלילה לראש העמוד