يعد نمط التصميم المفرد أحد أهم الأنماط وأكثرها استخدامًا في برمجة البرمجيات. فهو يضمن أن الفئة لديها مثيل واحد فقط أثناء تشغيل التطبيق وتوفر نقطة وصول عامة إلى هذا المثيل. في هذه المقالة، سنناقش أهمية Singleton، وكيفية تنفيذها في Golang، والفوائد التي تجلبها، خاصة في البيئات المتزامنة.
Singleton هو نمط تصميم يقيد مثيل فئة ما بمثيل واحد. وهو مفيد بشكل خاص في المواقف التي تتطلب نقطة تحكم واحدة أو موردًا مشتركًا واحدًا، مثل:
سأقوم بإدراج بعض النقاط حول التنفيذ من النموذج الأكثر منطقية وأيضًا لإظهار أنه ليس كل شيء ورديًا، وبعض المشاكل التي يمكن أن نواجهها معه.
لتنفيذ مفردة سأستخدم Golang. في هذه اللغة علينا أن نولي اهتمامًا خاصًا بالتزامن لضمان إنشاء مثيل واحد فقط، حتى عندما تحاول goroutines متعددة الوصول إلى المثيل في وقت واحد.
لجعل مثالنا أقرب إلى العالم الحقيقي، فلنقم بإنشاء مسجل لتطبيقنا. المُسجل هو أداة شائعة في التطبيقات التي يجب أن تكون فريدة لضمان اتساق السجل.
أولاً، نحدد البنية التي نريد أن يكون لها مثيل واحد.
package logger import ( "fmt" "sync" ) type Logger struct {} var loggerInstance *Logger
تكون وظيفة NewInstance مسؤولة عن إرجاع المثيل الفردي لبنية Singleton. نحن نستخدم كائن المزامنة (mutex) لضمان الأمان في البيئات المتزامنة، وتنفيذ قفل مزدوج التحقق لتحقيق الكفاءة.
package logger import ( "fmt" "sync" ) type Logger struct{} var logger *Logger var mtx = &sync.Mutex{} func NewInstance() *Logger { if logger == nil { mtx.Lock() defer mtx.Unlock() if logger == nil { fmt.Println("Creating new Logger") logger = &Logger{} } } else { fmt.Println("Logger already created") } return logger }
تحتوي أداة السجل دائمًا على بعض أنواع السجلات، مثل المعلومات لعرض المعلومات فقط، والخطأ لإظهار الأخطاء وما إلى ذلك. إنها طريقة أيضًا لتصفية نوع المعلومات التي نريد عرضها في تطبيقنا.
لذلك دعونا ننشئ طريقة تعرض سجلنا بنوع المعلومات. للقيام بذلك، سنقوم بإنشاء وظيفة ستتلقى رسالة السجل الخاصة بنا ونقوم بتنسيقها بتنسيق INFO.
package logger import ( "fmt" "sync" "time" ) const ( INFO string = "INFO" ) type Logger struct{} var logger *Logger var mtx = &sync.Mutex{} func NewInstance() *Logger { if logger == nil { mtx.Lock() defer mtx.Unlock() if logger == nil { fmt.Println("Creating new logger") logger = &Logger{} } } else { fmt.Println("Logger already created") } return logger } func (l *Logger) Info(message string) { fmt.Printf("%s - %s: %s\n", time.Now().UTC().Format(time.RFC3339Nano), INFO, message) }
ولاستخدام المسجل الجديد الخاص بنا، سنقوم بإنشاء مثيل له ضمن الحزمة الرئيسية لدينا وإنشاء سجل لمعرفة كيفية عمل هذا التنفيذ.
package main import ( "playground-go/pkg/logger" ) func main() { log := logger.NewInstance() log.Info("This is an example of log") }
هذه هي النتيجة عندما نقوم بتشغيل البرنامج:
Creating new logger 2024-07-03T19:34:57.609599Z - INFO: This is an example of log
إذا أردنا اختبار ما إذا كان NewInstance يضمن حقًا أنه سيكون لدينا مثيل واحد فقط قيد التشغيل، فيمكننا إجراء الاختبار التالي.
package main import ( "fmt" "playground-go/pkg/logger" ) func main() { log := logger.NewInstance() log.Info("This is an example of log") log2 := logger.NewInstance() log2.Info("This is another example of log") if log == log2 { fmt.Println("same instance") } else { fmt.Println("different instance") } }
لقد تغيرت سجلاتنا والآن يمكننا أن نرى أننا قمنا بحظر إنشاء مثيل جديد:
Creating new logger 2024-07-03T19:45:19.603783Z - INFO: This is an example of log Logger already created 2024-07-03T19:45:19.603793Z - INFO: This is another example of log same instance
يعد نمط Singleton أداة قوية لضمان وجود مثيل واحد فقط لفئة معينة أثناء وقت تشغيل التطبيق. في مثال المسجل، رأينا كيف يمكن تطبيق هذا النمط لضمان اتساق السجل عبر التطبيق.
آمل أن يساعدك هذا على فهم سينجلتون في جولانج بشكل أفضل.
تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.
Copyright© 2022 湘ICP备2022001581号-3