بسم الله الرحمن الرحيم
اقتداءا بموضوع أخي فيصل الردادي في منتدى الجافا, /index.php?showtopic=74039
نبدأ هذه السلسلة إن شاء الله.
أولا: ماذا تقصد بـ design pattern؟
العبارة تعني اشكال في تصميم اجزاء من البرامج تتكرر بكثرة. لتفهم المعنى اكثر, من الأفضل ان تنظر الى أمثلة لانواع مختلفة من الـ design patterns حتى تفهم الفكرة.
الـ pattern اللذي سنتناوله اليوم إن شاء الله هو الـ singleton
سيناريو المشكلة: صممنا برنامج معين, و البرنامج يحتوي على class أساسي في عمل البرنامج, و تبعا لطريقة عمل البرنامج, فإنه من غير المعقول وجود أكثر من نسخة واحدة من هذا الـ class في نفس الوقت, كما أننا نريد السماح بالوصول لهذا الكائن من أي مكان في البرنامج.
أمثلة على هذا: مثلا, كلاس اسمه application مهمته تمثيل البرنامج, او كلاس اسمه DataBase يمثل قاعدة البيانات, إذا كانت هناك قاعدة بيانات واحدة فقط! او مثلا, كائن اللاعب في لعبة يلعب فيها شخص واحد .. و هناك حالات كثيرة.
الحل:
اولا نريد ان نمنع أي شخص من إنشاء نسخة جديدة من الكلاس .. لعمل ذلك سوف نجعل الـ constructr نجعله private.
لنقم أولا بإنشاء الكلاس:
class Example
{
private:
public:
};و نضع الـ constructor تحت الـ private
class Example
{
private:
Example() //private, no one can istantiate this class!
{
}
public:
};و لكن اذا لم يكن بإمكان احد ان ينشئ نسخة من هذا الكلاس, فما فائدته؟ لا بد لنا من طريقة بحيث نقوم بإنشائه مرة واحدة, و من ثم نمنع أي شخص من إنشاء نسخة جديدة.
لحسن الحظ ان الكلاس نفسه يستطيع إنشاء نفسه!
سنقوم بوضع function جديد داخل الكلاس, و لكنه سيكون static, و سيقوم بإنشاء نسخة من هذا الكائن, و حفظه في مؤشر, و سيكون ايضا static
class Example
{
private:
Example() //private, no one can instantiate this class!
{
}
static Example * instance; //the only instance that will exist
static void createInstance()
{
instance = new Example();
}
public:
};و لكن كل شيء لا يزال private!! لا بد لنا من طريقة للسماح ببقية البرنامج بانشاء الكائن و استخدامه!
و لكن لحظة, إذا قمنا بإنشائه مرة .. ألن يكون بإمكاننا إنشائه عدة مرات؟
إذا, لتلافي هذا الأمر, سنقوم بوضع دالة تقوم بالتأكد فيما إذا كنا قد أنشأنا الكائن أم لا, فإذا كنا قد أنشئناه, فإنها لن تفعل شيئا, و إذا لم نكن قد أنشئناه بعد, ستقوم بإنشاء الكائن.
class Example
{
private:
Example() //private, no one can istantiate this class!
{
}
static Example * instance; //the only instance that will exist
static void createInstance()
{
instance = new Example();
}
public:
static void instantiate()
{
if( instance == 0 )
{
createInstance();
}
}
};و لكن لحظة, يجب اولا ان نقوم بعمل initialization للمؤشر instance بحيث يكون في البداية 0
لعمل ذلك يجب وضع هذا السطر خارج تعريف الكلاس:
Example * Example::instance = 0;
الان اكتمل المثال تقريبا, سنقوم فقط بتغيير بسيط للدالة instantiate بحيث تقوم بإعطائنا مؤشر للكائن, و ايضا سنغير اسمها لان مهمتها تغيرت:
class Example
{
private:
Example() //private, no one can istantiate this class!
{
}
static Example * instance; //the only instance that will exist
static void createInstance()
{
instance = new Example();
}
public:
static Example * getInstance()
{
if( instance == 0 )
{
createInstance();
}
return instance;
}
};
Example * Example::instance = 0;و الان لدينا كلاس لا يمكن الا انشاء نسخة واحدة منه, و يمكن لأي شخص في العالم الحصول على هذه النسخة عن طريق:
Example * e = Example::getInstance(); //get the singleton instance
و هذا مثال كامل, قابل للترجمة او عمل compile عليه, و قمت فيه بإضافة عضو صغير الى الكلاس للتجربة!
#include <iostream>
using namespace std;
class Example
{
char * x;
private:
Example() //private, no one can istantiate this class!
{
x = "hello world";
}
static Example * instance; //the only instance that will exist
static void createInstance()
{
instance = new Example();
}
public:
static Example * getInstance()
{
if( instance == 0 )
{
createInstance();
}
return instance;
}
void printMsg()
{
cout << x << endl;
}
};
Example * Example::instance = 0;
int main()
{
Example * e = Example::getInstance(); //get the singleton instance
e->printMsg();
return 0;
}