
الوقت المقدر للقراءة 10 دقيقة.
وصف النموذج
هو نموذج إنشائي يستخدم لضمان الحصول على كائن وحيد من صف معين ومنع الصفوف الأخرى من إنشاء أكثر من كائن من هذا الصف حيث يقوم الجميع باستخدام الكائن الوحيد بدل أن يقوم كل واحد بإنشاء كائن خاص به.
لفهم أكثر تابع الشكل التالي:
لنفرض أنه لدينا الصف مدرس الذي يستطيع إلقاء درس ولنفرض أنه لدينا الصف طالب والذي يحتاج لكائن من الصف مدرس من اجل تلقّي الدرس.
في الصورة اليمينية تظهر الحالة العادية بدون استخدام النموذج Singleton حيث يقوم كل طالب بإنشاء كائن خاص به من الصف مدرس وينتج عن ذلك إنشاء عدة كائنات من الصف مدرس.
في الصورة اليسارية والتي تمثل النموذج Singleton نلاحظ إنشاء كائن واحد من الصف مدرس ويكون مشترك بين جميع الطلاب.
متى نستخدم النموذج Singleton
يفضل استخدام هذه النموذج في صف معين عندما تكون عملية إنشاء كائن من هذا الصف مكلفة إما من ناحية الزمن (عملية الإنشاء تستغرق وقتاً طويلاً) أو من ناحية الموارد (عملية الإنشاء تستهلك الكثير من الذاكرة والمعالجة)، أيضاً يمكن استخدام هذا النموذج في أي صف يتطلب وجود كائن وحيد.
كيفية تطبيق النموذج Singleton
هناك أكثر من طريقة لتطبيق هذا النموذج وقد تختلف حسب لغة البرمجة المستخدمة سأكتفي بذكر طريقة واحدة باستخدام جافا.
بفرض لدينا الصف Singleton نتبع الخطوات التالية: داخل الصف Singleton نقوم بإنشاء عضو بياني وليكن اسمه instance كما يلي
class Singleton {
private static Singleton instance = null;
ويجب الانتباه أن يكون هذا العضو البياني private لمنع الوصول المباشر من خارج الصف ويجب أن يكون أيضاً static حتى يكون مشترك بين جميع أغراض الصف. الخطوة التالية هي إنشاء باني Constructor بجسم فارغ ومحدد وصول private وهي خطوة مهمة جداً الهدف الوحيد منها هو منع أي صف خارجي من إنشاء كائنات من الصف Singleton بشكل مباشر واجبارهم على استخدام الدالة getInstance.
private Singleton() {
}
الخطوة الأخيرة إنشاء الدالة getInstance كما يلي
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
الطريقة الآلية
باستخدام برنامج Netbeans إذهب إلى القائمة
File->New File->Java->Java singleton class
إضغط على التالي وأعط هذا الصف إسماً وليكن مثلاً NewSingleton وستحصل على الكود التالي:
/**
*
* @author Mutasem
*/
public class NewSingleton {
private NewSingleton() {
}
public static NewSingleton getInstance() {
return NewSingletonHolder.INSTANCE;
}
private static class NewSingletonHolder {
private static final NewSingleton INSTANCE = new NewSingleton();
}
}
مثال للتوضيح
ليكن لدينا الصف Connection مهمته إجراء عملية اتصال معينة، وليكن لدينا صف آخر يستخدم الصف Connection لإجراء عملية الاتصال عن طريق إنشاء كائن من الصف Connection واستدعاء الدالة connect.
من أجل ملاحظة الفرق بشكل واضح سأقوم بكتابة كود تأخير زمني لمدة 2 ثانية في الباني الخاص بالصف Connection ومن ثم تنفيذ البرنامج باستخدام النموذج Singleton ومرة أخرى بدون هذا النموذج.
التنفيذ باستخدام النموذج
/**
*
* @author Mutasem
*/
public class Connection {
private static Connection instance = null;
private Connection() {
try {
System.out.println("Construction");
Thread.sleep(2000);
} catch (InterruptedException ex) {
Logger.getLogger(Connection.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static Connection getInstance() {
if (instance == null) {
instance = new Connection();
}
return instance;
}
public void connect() {
System.out.println("Connecting");
}
}
/******************************************/
/**
*
* @author Mutasem
*/
public class Clients {
public static void main(String[] args) {
Connection client1 = Connection.getInstance();
Connection client2 = Connection.getInstance();
Connection client3 = Connection.getInstance();
Connection client4 = Connection.getInstance();
client1.connect();
client2.connect();
client3.connect();
client4.connect();
}
}
بدون استخدام النموذج
/**
*
* @author Mutasem
*/
public class Connection {
private static Connection instance = null;
public Connection() {
try {
System.out.println("Construction");
Thread.sleep(2000);
} catch (InterruptedException ex) {
Logger.getLogger(Connection.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void connect() {
System.out.println("Connecting");
}
}
/******************************************/
/**
*
* @author Mutasem
*/
public class Clients {
public static void main(String[] args) {
Connection client1 = new Connection();
Connection client2 = new Connection();
Connection client3 = new Connection();
Connection client4 = new Connection();
client1.connect();
client2.connect();
client3.connect();
client4.connect();
}
}
قم بتجربة المشروع على جهازك الحاسب باستخدام برنامج Netbeans ولاحظ الفرق في زمن التنفيذ.
رابط السلسلة على GitHub
https://github.com/mutasemhajhasan/Design-Patterns
المراجع
Gamma, Erich ; Helm, Richard ; Johnson , Ralph ; Vlissides , John;. (1994). Design Patterns: Elements of Reusable Object-Oriented Software. Hawthorne, New York: Addison-Wesley.