Menu
Coddy logo textTech

Singleton בטוח לריבוי תהליכונים

חלק מהיחידה תכנות מונחה עצמים במסלול ה-C# של Coddy. שיעור 52 מתוך 70.

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

Singleton בסיסי משתמש בבנאי פרטי כדי למנוע יצירה של מופעים מבחוץ ובמאפיין סטטי כדי לספק גישה:

public class Logger
{
    private static Logger _instance;
    private static readonly object _lock = new object();
    
    private Logger() { }  // בנאי פרטי
    
    public static Logger Instance
    {
        get
        {
            lock (_lock)
            {
                if (_instance == null)
                    _instance = new Logger();
                return _instance;
            }
        }
    }
    
    public void Log(string message) => Console.WriteLine(message);
}

הפקודה lock מבטיחה בטיחות בתהליכונים — אם כמה תהליכונים מנסים לגשת אל Instance בו־זמנית, רק אחד מהם יכול להיכנס למקטע הקריטי בכל פעם. בלי זה, שני תהליכונים עלולים לראות ש־_instance הוא null וליצור מופעים נפרדים.

C# מציעה גישה פשוטה יותר ובטוחה לשימוש בתהליכונים, באמצעות אתחול סטטי:

public class Logger
{
    private static readonly Logger _instance = new Logger();
    
    private Logger() { }
    
    public static Logger Instance => _instance;
    
    public void Log(string message) => Console.WriteLine(message);
}

גרסה זו בטוחה לשימוש במקביל, כי ה־CLR מבטיח שאתחול של שדות סטטיים מתבצע פעם אחת בלבד. שתי הגישות מבטיחות שתקבלו תמיד את אותו מופע:

Logger.Instance.Log("First call");
Logger.Instance.Log("Same instance");
challenge icon

אתגר

קל

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

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

  • ConfigManager.cs: צרו מחלקה בשם ConfigManager במרחב השמות Configuration, שמממשת את תבנית Singleton. מנהל התצורה שלכם צריך:
    • להכיל שדה סטטי פרטי שישמור את המופע היחיד
    • להשתמש בבנאי פרטי כדי למנוע יצירת מופעים חיצונית
    • לספק מאפיין סטטי Instance שמחזיר את המופע היחיד (השתמשו בגישה הפשוטה יותר של אתחול סטטי כדי להבטיח בטיחות בשימוש במקביל)
    • להכיל שדה מחרוזת פרטי _appName שמאותחל לערך "MyApp"
    • להכיל מתודה SetAppName(string name) לעדכון שם היישום
    • להכיל מתודה GetAppName() שמחזירה את שם היישום הנוכחי
  • Program.cs: בקובץ הראשי שלכם, הדגימו ש-Singleton פועל כראוי באמצעות גישה למופע כמה פעמים והצגה שהשינויים נשמרים בכל ההפניות.

תקבלו קלט אחד:

  • שם יישום חדש להגדרה (לדוגמה, ProductionServer)

בתוכנית שלכם:

  1. קבלו את המופע של ConfigManager והדפיסו את שם היישום שמוגדר כברירת מחדל
  2. קבלו שוב את המופע (לתוך משתנה אחר) והשתמשו בו כדי להגדיר את שם היישום החדש מהקלט
  3. קבלו את המופע בפעם השלישית והדפיסו את שם היישום כדי להוכיח שכל ההפניות חולקות את אותם נתונים

לדוגמה, אם הקלט הוא ProductionServer, הפלט צריך להיות:

MyApp
ProductionServer

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

נסו בעצמכם

using System;
using Configuration;

class Program
{
    public static void Main(string[] args)
    {
        // קראו את הקלט - שם היישום החדש
        string newAppName = Console.ReadLine();
        
        // TODO: קבלו את המופע של ConfigManager והדפיסו את שם היישום המוגדר כברירת מחדל
        
        // TODO: קבלו שוב את המופע (לתוך משתנה אחר) והשתמשו בו כדי להגדיר את שם היישום החדש
        
        // TODO: קבלו את המופע בפעם השלישית והדפיסו את שם היישום כדי להוכיח שכל ההפניות חולקות את אותם נתונים
    }
}
quiz iconבחנו את עצמכם

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

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

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