Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

نمط Singleton الآمن للخيوط (Thread-Safe)

جزء من قسم Object Oriented Programming في رحلة C# على Coddy — الدرس 52 من 70.

يضمن نمط Singleton أن للفئة مثيلاً واحدًا فقط طوال تطبيقك ويوفر نقطة وصول عامة إليه. وهذا مفيد لإدارة الموارد المشتركة مثل إعدادات التكوين، أو خدمات تسجيل الأحداث، أو اتصالات قاعدة البيانات.

يستخدم نمط Singleton الأساسي منشئًا خاصًا (private constructor) لمنع إنشاء كائنات خارجية وخاصية ثابتة (static property) لتوفير الوصول:

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 سلامة الخيوط (thread safety) - إذا حاولت خيوط متعددة الوصول إلى Instance في وقت واحد، يمكن لخيط واحد فقط الدخول إلى القسم الحرج في كل مرة. بدون ذلك، يمكن لخيطين رؤية _instance كقيمة فارغة (null) وإنشاء مثيلات منفصلة.

تقدم لغة C# نهجاً أكثر بساطة وأماناً للخيوط (thread-safe) باستخدام التهيئة الثابتة (static initialization):

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);
}

هذا الإصدار آمن من حيث تعدد الخيوط (thread-safe) لأن الـ CLR يضمن أن تهيئة الحقول الثابتة (static field initialization) تحدث مرة واحدة فقط. كلا النهجين يضمنان حصولك دائمًا على نفس المثيل (instance):

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

التحدي

سهل

لنقم ببناء مدير إعدادات (configuration manager) آمن للخيوط (thread-safe) باستخدام نمط Singleton. في التطبيقات الحقيقية، يجب أن تكون إعدادات التكوين قابلة للوصول في جميع أنحاء البرنامج مع ضمان وجود مثيل واحد فقط - وهي حالة استخدام مثالية لنمط Singleton.

ستقوم بتنظيم الكود الخاص بك عبر ملفين:

  • ConfigManager.cs: أنشئ فئة ConfigManager داخل مساحة الأسماء Configuration التي تطبق نمط Singleton. يجب أن يقوم مدير الإعدادات الخاص بك بما يلي:
    • امتلاك حقل ثابت خاص (private static field) للاحتفاظ بالمثيل الوحيد.
    • استخدام منشئ خاص (private constructor) لمنع إنشاء مثيلات خارجية.
    • توفير خاصية 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اختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس Object Oriented Programming