نمط 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");التحدي
سهللنقم ببناء مدير إعدادات (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).
في برنامجك:
- احصل على مثيل
ConfigManagerواطبع اسم التطبيق الافتراضي. - احصل على المثيل مرة أخرى (في متغير مختلف) واستخدمه لتعيين اسم التطبيق الجديد من المدخلات.
- احصل على المثيل للمرة الثالثة واطبع اسم التطبيق لإثبات أن جميع المراجع تشترك في نفس البيانات.
على سبيل المثال، إذا كان المدخل هو 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: احصل على المثيل للمرة الثالثة واطبع اسم التطبيق لإثبات أن جميع المراجع تشترك في نفس البيانات
}
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات OOP
الملفات الخارجيةNamespaces والتوجيهاتمقدمة في Classes و Objectsالكلمة المفتاحية 'this'Methods والمعاملاتFields مقابل PropertiesConstructorsObject Initializersمراجعة - آلة حاسبة بسيطة4الوراثة
صيغة الوراثة الأساسية (:)الكلمة المفتاحية 'base'الكلمات المفتاحية Virtual و Overrideالأصناف المختومة (Sealed Classes)الفئة الأساسية 'object'مراجعة - هيكلية الموظفين7ميزات متقدمة
تحميل العوامل (Operator Overloading)المفهرسات (Indexers (this[]))إعادة تعريف ()ToStringدوال التوسعة (Extension Methods)ملخص - Custom List10أنماط التصميم - الجزء الأول
مقدمة في أنماط التصميمنمط Singleton الآمن للخيوط (Thread-Safe)نمط المصنع (Factory Pattern)نمط المراقب (Events)نمط الاستراتيجية (Strategy Pattern)2الخصائص والأعضاء الساكنة (Static Members)
الخصائص المطبقة تلقائيًا (Auto-Implemented Properties)خصائص القراءة فقط والكتابة فقطالحقول والدوال الساكنة (Static)الفئات الساكنة (Static Classes)الأعضاء ذات البنية التعبيرية (Expression-Bodied Members)5تعدد الأشكال والواجهات (Polymorphism & Interfaces)
تعدد الأشكال: وقت التجميع مقابل وقت التشغيلالواجهة مقابل الفئة المجردة (Abstract Class)الواجهات المتعددةالواجهات الصريحةUpcasting و Downcastingملخص - حاسبة الأشكال8مفاهيم البرمجة كائنية التوجه (OOP) المتقدمة
التركيب بدلاً من الوراثةالـ Generics (الأصناف والدوال)الـ Delegates والأحداثالـ Attributes والـ Reflectionواجهة IDisposable وجملة usingأساسيات Dependency Injection