לא מזמן התווכחתי עם עמיתים לעבודה בנוגע לתבנית עיצוב 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 לא היתה מוצדקת.
4 תגובות
דבר ראשון תודה רבה על האתר הוא ממש פרקטי המדריכים ממש עזרו לי !
דבר שני רציתי לשאול האם מתוכנן מדריך 1. לbootstrap
2. Angular
תודה רבה!!!
תודה רבה!
בתכנון כרגע מדריך ל-ES6 ואז לאנגולר. מבטיח.
היי 🙂
בסוף ראיתי שעשית מדריך לריאקט אבל לא ראיתי אחד לאנגולר.
למה בחרת בריאקט? והאם מתוכנן עדיין אחד לאנגולר?
תודה רבה
סינגלטון נחשב בעיני רבים כאנטיפאטרן (תבנית שאין להשתמש בה) ובעיני אחרים כתבנית שיש להשתמש בה רק כשאין פתרון אחר. הרשת מלאה בהסברים על כך.
גם במקרה של בסיס נתונים, אין סיבה להשתמש בה. היא מגבילה אותנו לשימוש בבסיס נתונים אחד.