نمط التصميم سنجلتون (الوحداني) Singleton Design Pattern

 

في هذه المقالة القصيرة سوف نتعرف على نموذج التصميم سنجلتون (تعني الوحيد من نوعه)، وهذه فعلا مفهوم نمط التصميم الذي سوف نتعرف إليه. الفكرة من هذا النمط هو تشيد أو بناء صف (كلاس) يكون وحيد ولا يمكن إيجاد سوى نسخة وحيده منه. يستخدم نمط التصميم هذا عندما يكون لدينا بيانات ثابتة ومشتركة في البرنامج الواحد. ربما يتبادر إلى ذهنك الآن أن هذا ممكنا باستخدام الصفوف الستاتيكية، وهذا كلام صحيح إذ أنه يمكنك استخدام الصفوف الستاتيكية للإحتفاظ بنسخة وحيدة من البيانات ومشاركتها بين جميع صفوف أو وحدات البرنامج دون الحاجة ولا حتى المقدرة على انشاء عدة نسخ منه. لكن ليس هذا هدف هذه المقالة ، هدف هذه المقالة هو التعرف على كيفية بناء صف عادي (ليس ستاتيكي) لتحقيق شيء مماثل للصفوف الستاتيكية وزيادة. الزيادة التي أعنيها هنا هي أن بناء صف عادي سوف يقدم لك مزايا لا تتوفر في الصفوف الستاتيكية. أرجوا أن أكون باختصار قد قدمت لك فكرة نمط التصميم "الوحيد" سنجلتون. الآن سوف نبدأ التعرف كيف نحقق ذلك برمجيا باستخدام لغة السي شارب. لاحظ كود 1 الذي يوضح الهيكل البدائي لإنشاء صف من نمط التصميم سنجلتون. تم تعريف الباني "constructor" بأنه خاص حتى لا يستطيع أحد إنشاء نسخة منه باستدعاء البناني ولو حتى مرة واحدة من خارج الصف. طبعا حاليا الصف بصيغته الحالية لن يمكن أحد من إنشاء نسخة منه بسبب التحفظ على البناني للإستخدام الداخلي ضمن نفس الكلاس فقط.

كود 1 الهيكل البدائي لانشاء صف من نمط سنجلتون

public class Singleton
{
    private Singleton() { }
}

الآن سوف نعرف خاصيّة تمكن مستخدم هذا الصف من التعامل مع نسخة من هذا الصف ولتهيئة نسخة من الصف داخليا في حال لم يتم ذلك بعد

كود 2: إضافة الباني وخاصية للحصول على نسخة وحيدة من الصف

1 public class Singleton
2 {
3      private static Singleton instance;
4      private Singleton() { }
5
6      public static Singleton Instance
7      {
8           get
9           {
10              if (instance == null)
11              {
12                   instance = new Singleton();
13              }
14
15                  return instance;
16          }
17     }
18 }

والآن أصبح الصف شبه جاهز حيث أن الخاصية Instance سوف تكون بمثابة الواجهة للصفوف الأخرى. الخاصية Instance سوف تعيد نسخة من الصف الحالي Singleton في حال توفرها، وإن لم تتوفر ستقوم باستدعاء الباني ليتم بتجهيز نسخة من الصف وتمريرها. وبما أن نوع الحقل هو ستاتيك فسوف نضمن أن هذه القيمة ستكون وحيدة. مرة أخرى الصف شبه جاهز، لأن مازال هناك احتمال حدوث أكثر من نسخة من الصف في حالة multi-threading، حيث أنه من المحتمل أن يتم فحص الشرط instance == null في نفس الوقت من قبل أكثر من thread، وبالتالي هذا سيؤدي إلى إنشاء أكثر من نسخة من الصف. لحل المشكلة السابقة سيتم استخدام تقنية lock في السي شارب التي تضمن السماح لـ thread واحد فقط بعمل الفحص وإنشاء نسخة من الصف في حال أن ذلك لم يحدث سابقا. بعد التعديل الكود السابق، سيصبح الكود الجديد المبين في

1 using System;
2
3 public class Singleton
4 {
5      private static object syncRoot = new Object();
6      private static Singleton instance;
7      private Singleton() { }
8
9      public static Singleton Instance
10    {
11         get
12         {
13               if (instance == null)
14               {
15                     lock (syncRoot)
16                     {
17                          if (instance == null)
18                          {
19                               instance = new Singleton();
20                           }
21                      }
22                }
23
24                return instance;
25          }
26     }
27 }

أصبح الكود الآن آمن للإستخدام مع multi-threads، لاحظ السطر 13 و 15، في هذه الحالة سوف يتم السماح لـ thread واحد فقط بالعبور وإنشاء نسخة من الصف في حال أن ذلك لم يحدث سابقا. قد تتساءل ما الفائدة من وجود شرط الفحص في السطر 13 وذلك لعدم السماح بتعطيل threads ، حيث أن بدون هذا الشرط سيؤدي إلى تنفيذ أمر القفل (السطر 14) كل مرة يتم فيها استدعاء الخاصية وبالتالي سيؤدي إلى توقف الـ threads الأخرى (إن وجدت) عن العمل ريثما يتم تحرير القفل. أخيرا قد تتساءل حسنا فما الفائدة من تكرار شرط الفحص في السطر 17، لأنه إذا فرضنا أن أكثر من thread استطاع اجتياز الشرط الأول (طبعا هذا وارد الحدوث في المرة الأولى التي يتم فيها استخدام الصف) وبالتالي ستقوم الـ thread الأولى بإنشاء نسخة من الصف بينما تنتظر الـ thread الأخرى تحرير القفل لتقوم هي مرة أخرى بإنشاء نسخة جديدة ثانية، وهكذا. لتجنب هذا الأمر فإنه سوف يتم إعادة فحص الشرط للتأكد أنه لم يقم thread سابق بإنشاء نسخة من الصنف قبل ذلك. مرة أخرى هذا وارد الحدوث فقط في حال multi-threading ولا يوجد نسخة للصف سابقا.

أرجوا أن أكون قد وفقت في الشرح

أضطررت لإستخدام المصطلحات الانجليزية لتفادي الوقوع في المشاكل جراء الترجمة لأن الأكثر يتبع المصطلحات الانجليزية.

المراجع:

Implementing Singleton in C#: https://msdn.microsoft.com/en-us/library/ff650316.aspx

أضف تعليقاً

إملأ الحقول أدناه بالمعلومات المناسبة أو إضغط على إحدى الأيقونات لتسجيل الدخول:

WordPress.com Logo

أنت تعلق بإستخدام حساب WordPress.com. تسجيل خروج   / تغيير )

صورة تويتر

أنت تعلق بإستخدام حساب Twitter. تسجيل خروج   / تغيير )

Facebook photo

أنت تعلق بإستخدام حساب Facebook. تسجيل خروج   / تغيير )

Google+ photo

أنت تعلق بإستخدام حساب Google+. تسجيل خروج   / تغيير )

Connecting to %s