"إذا أراد العامل أن يؤدي عمله بشكل جيد، فعليه أولاً أن يشحذ أدواته." - كونفوشيوس، "مختارات كونفوشيوس. لو لينجونج"
الصفحة الأمامية > برمجة > نمط تصميم سينجلتون

نمط تصميم سينجلتون

تم النشر بتاريخ 2024-07-30
تصفح:562

Singleton Design Pattern

يعد نمط التصميم المفرد أحد أهم الأنماط وأكثرها استخدامًا في برمجة البرمجيات. فهو يضمن أن الفئة لديها مثيل واحد فقط أثناء تشغيل التطبيق وتوفر نقطة وصول عامة إلى هذا المثيل. في هذه المقالة، سنناقش أهمية Singleton، وكيفية تنفيذها في Golang، والفوائد التي تجلبها، خاصة في البيئات المتزامنة.

ما هو سينجلتون؟

Singleton هو نمط تصميم يقيد مثيل فئة ما بمثيل واحد. وهو مفيد بشكل خاص في المواقف التي تتطلب نقطة تحكم واحدة أو موردًا مشتركًا واحدًا، مثل:

  • مديرو التكوين، حيث تحتاج إعدادات التطبيق إلى أن تكون مركزية.
  • تجمعات اتصال قاعدة البيانات، حيث يجب إدارة عدد محدود من الاتصالات بكفاءة.
  • أدوات قطع الأشجار، حيث يكون اتساق السجل أمرًا بالغ الأهمية.

لماذا استخدام سينجلتون؟

سأقوم بإدراج بعض النقاط حول التنفيذ من النموذج الأكثر منطقية وأيضًا لإظهار أنه ليس كل شيء ورديًا، وبعض المشاكل التي يمكن أن نواجهها معه.

فوائد

  • الاتساق العالمي: يضمن أن جميع نقاط التطبيق تستخدم نفس المثيل، مما يوفر اتساق البيانات والسلوك.
  • التحكم في الوصول: التحكم المركزي في الإنشاء والوصول إلى المثيل، مما يسهل صيانة وإدارة دورة حياة الكائن.
  • كفاءة الموارد: يتجنب الإنشاء غير الضروري لمثيلات متعددة، مما يوفر الذاكرة وموارد المعالجة.

سلبيات

  • صعوبة الاختبار: يمكن للمفردات أن تجعل اختبارات وحدة الكتابة أكثر صعوبة لأنها تقدم حالات عالمية تحتاج إلى إدارتها.
  • زيادة الاقتران: الاستخدام المفرط للمفردات يمكن أن يؤدي إلى اقتران أكثر إحكامًا بين المكونات، مما يجعل من الصعب صيانة التطبيق وتطويره.

تنفيذ سينجلتون

لتنفيذ مفردة سأستخدم Golang. في هذه اللغة علينا أن نولي اهتمامًا خاصًا بالتزامن لضمان إنشاء مثيل واحد فقط، حتى عندما تحاول goroutines متعددة الوصول إلى المثيل في وقت واحد.

لجعل مثالنا أقرب إلى العالم الحقيقي، فلنقم بإنشاء مسجل لتطبيقنا. المُسجل هو أداة شائعة في التطبيقات التي يجب أن تكون فريدة لضمان اتساق السجل.

1- تعريف الهيكل

أولاً، نحدد البنية التي نريد أن يكون لها مثيل واحد.

package logger

import (
    "fmt"
    "sync"
)

type Logger struct {}

var loggerInstance *Logger

2 - تنفيذ وظيفة NewInstance

تكون وظيفة 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
}

3 - تنفيذ أنواع السجل

تحتوي أداة السجل دائمًا على بعض أنواع السجلات، مثل المعلومات لعرض المعلومات فقط، والخطأ لإظهار الأخطاء وما إلى ذلك. إنها طريقة أيضًا لتصفية نوع المعلومات التي نريد عرضها في تطبيقنا.

لذلك دعونا ننشئ طريقة تعرض سجلنا بنوع المعلومات. للقيام بذلك، سنقوم بإنشاء وظيفة ستتلقى رسالة السجل الخاصة بنا ونقوم بتنسيقها بتنسيق 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)
}

4 - استخدام المسجل

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

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 أداة قوية لضمان وجود مثيل واحد فقط لفئة معينة أثناء وقت تشغيل التطبيق. في مثال المسجل، رأينا كيف يمكن تطبيق هذا النمط لضمان اتساق السجل عبر التطبيق.

آمل أن يساعدك هذا على فهم سينجلتون في جولانج بشكل أفضل.

بيان الافراج تم نشر هذه المقالة على: https://dev.to/rflpazini/singleton-design-pattern-1n51?1 إذا كان هناك أي انتهاك، يرجى الاتصال بـ [email protected] لحذفه
أحدث البرنامج التعليمي أكثر>

تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.

Copyright© 2022 湘ICP备2022001581号-3