ما هو المفرد؟
يعد المفرد أحد أبسط أنماط التصميم التي يمكن تطبيقها على الفصل الدراسي. يقول الناس أحيانًا "هذه الفئة مفردة"، مما يعني أن هذه الفئة تطبق نمط التصميم المفرد. في بعض الأحيان يكون من الضروري كتابة فئة يمكن إنشاء كائن واحد فقط لها. على سبيل المثال، فئة مسؤولة عن التسجيل أو الاتصال بقاعدة بيانات. يصف نمط تصميم Singleton كيف يمكننا إنجاز مثل هذه المهمة. المفرد هو نمط تصميم يقوم بأمرين:-
يوفر ضمانًا بأن الفصل سيحتوي على مثيل واحد فقط من الفصل.
-
يوفر نقطة وصول عالمية لمثيل هذه الفئة.
-
منشئ خاص. يقيد القدرة على إنشاء كائنات فئة خارج الفئة نفسها.
-
طريقة ثابتة عامة تقوم بإرجاع مثيل للفئة. هذه الطريقة تسمى
getInstance
. هذه هي نقطة الوصول العالمية إلى مثيل الفئة.
خيارات التنفيذ
يتم استخدام نمط التصميم المفرد بطرق مختلفة. كل خيار جيد وسيئ بطريقته الخاصة. هنا، كما هو الحال دائما: لا يوجد مثالي، ولكن عليك أن تسعى جاهدة لتحقيق ذلك. لكن أولاً، دعونا نحدد ما هو الجيد وما هو السيئ، وما هي المقاييس التي تؤثر على تقييم تنفيذ نمط التصميم. لنبدأ بالإيجابية. فيما يلي المعايير التي تعطي التنفيذ جاذبية وجاذبية:-
التهيئة البطيئة: عندما يتم تحميل الفصل أثناء تشغيل التطبيق عند الحاجة إليه بالضبط.
-
بساطة وشفافية الكود: المقياس بالطبع ذاتي ولكنه مهم.
-
سلامة الخيط: يعمل بشكل صحيح في بيئة متعددة الخيوط.
-
أداء عالي في بيئة متعددة الخيوط: تحظر الخيوط بعضها البعض بشكل طفيف أو لا تحظرها على الإطلاق عند مشاركة المورد.
-
التهيئة غير الكسولة: عندما يتم تحميل الفصل عند بدء تشغيل التطبيق، بغض النظر عما إذا كانت هناك حاجة إليه أم لا (مفارقة، في عالم تكنولوجيا المعلومات من الأفضل أن تكون كسولًا)
-
التعقيد وضعف إمكانية قراءة الكود. المقياس هو أيضا ذاتي. وسنفترض أنه إذا خرج الدم من العيون فإن التنفيذ يكون كذلك.
-
عدم سلامة الخيط. وبعبارة أخرى، "خطر الخيط". عملية غير صحيحة في بيئة متعددة الخيوط.
-
أداء ضعيف في بيئة متعددة الخيوط: تحظر سلاسل العمليات بعضها البعض طوال الوقت أو في كثير من الأحيان عند مشاركة المورد.
شفرة
نحن الآن على استعداد للنظر في خيارات التنفيذ المختلفة، مع ذكر الإيجابيات والسلبيات:حل بسيط
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return INSTANCE;
}
}
أبسط التنفيذ. الايجابيات:
-
بساطة وشفافية الكود
-
سلامة الخيط
-
أداء عالي في بيئة متعددة الخيوط
- لا التهيئة كسول.
التهيئة البطيئة
public class Singleton {
private static Singleton INSTANCE;
private Singleton() {}
public static Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
الايجابيات:
-
التهيئة البطيئة.
-
ليست آمنة للخيط
ملحق متزامن
public class Singleton {
private static Singleton INSTANCE;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
الايجابيات:
-
التهيئة البطيئة.
-
سلامة الخيط
-
ضعف الأداء في بيئة متعددة الخيوط
getInstance
تمت مزامنة الطريقة، ولا يمكنك إدخالها إلا مرة واحدة. في الواقع، لا نحتاج إلى مزامنة الطريقة بأكملها، ولكن فقط ذلك الجزء منها الذي نقوم فيه بتهيئة كائن فئة جديد. لكن لا يمكننا ببساطة تغليف synchronized
الجزء المسؤول عن إنشاء كائن جديد في كتلة: فهذا لن يوفر أمانًا للخيط. الأمر أكثر تعقيدًا بعض الشيء. طريقة المزامنة الصحيحة موضحة أدناه:
قفل مزدوج التحقق
public class Singleton {
private static Singleton INSTANCE;
private Singleton() {
}
public static Singleton getInstance() {
if (INSTANCE == null) {
synchronized (Singleton.class) {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}
الايجابيات:
-
التهيئة البطيئة.
-
سلامة الخيط
-
أداء عالي في بيئة متعددة الخيوط
-
غير مدعوم في إصدارات Java الأقل من 1.5 (تم إصلاح الكلمة الأساسية المتغيرة في الإصدار 1.5)
INSTANCE
يجب أن يكون المتغير إما final
أو volatile
. التنفيذ الأخير الذي سنناقشه اليوم هو Class Holder Singleton
.
حامل الطبقة سينجلتون
public class Singleton {
private Singleton() {
}
private static class SingletonHolder {
public static final Singleton HOLDER_INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.HOLDER_INSTANCE;
}
}
الايجابيات:
-
التهيئة البطيئة.
-
سلامة الخيط.
-
أداء عالي في بيئة متعددة الخيوط.
-
للتشغيل الصحيح، من الضروري التأكد من
Singleton
تهيئة كائن الفئة دون أخطاء. وإلا فإن استدعاء الطريقة الأولgetInstance
سينتهي بخطأExceptionInInitializerError
، وستفشل جميع الاستدعاءات اللاحقةNoClassDefFoundError
.
تطبيق | التهيئة البطيئة | سلامة الخيط | سرعة تعدد الخيوط | متى يجب استخدام؟ |
---|---|---|---|---|
حل بسيط | - | + | سريع | أبداً. أو عندما لا تكون التهيئة البطيئة مهمة. ولكن أبدا أفضل. |
التهيئة البطيئة | + | - | غير قابل للتطبيق | دائمًا عندما لا تكون هناك حاجة إلى تعدد العمليات |
ملحق متزامن | + | + | ببطء | أبداً. أو عندما لا تكون سرعة العمل مع مؤشرات الترابط المتعددة مهمة. ولكن أبدا أفضل |
قفل مزدوج التحقق | + | + | سريع | في حالات نادرة عندما تحتاج إلى التعامل مع الاستثناءات عند إنشاء مفردة. (عندما لا يكون الفصل المفرد لحامل الفئة قابلاً للتطبيق) |
حامل الطبقة سينجلتون | + | + | سريع | دائمًا عندما تكون هناك حاجة إلى تعدد مؤشرات الترابط ويكون هناك ضمان بأنه سيتم إنشاء كائن فئة مفردة دون مشاكل. |
إيجابيات وسلبيات نمط سينجلتون
بشكل عام، يقوم المفرد بالضبط بما هو متوقع منه:-
يوفر ضمانًا بأن الفصل سيحتوي على مثيل واحد فقط من الفصل.
-
يوفر نقطة وصول عالمية لمثيل هذه الفئة.
-
تنتهك Singleton SRP (مبدأ المسؤولية الفردية) - تتحكم فئة Singleton، بالإضافة إلى مسؤولياتها المباشرة، في عدد نسخها.
-
إن اعتماد الفصل أو الطريقة العادية على المفردة غير مرئي في العقد العام للفئة.
-
المتغيرات العالمية سيئة. يتحول المفرد في النهاية إلى متغير عالمي ضخم.
-
يؤدي وجود المفرد إلى تقليل قابلية اختبار التطبيق بشكل عام والفئات التي تستخدم المفرد بشكل خاص.
GO TO FULL VERSION