Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

نمط Singleton

جزء من قسم البرمجة كائنية التوجه في رحلة Java على Coddy. الدرس 65 من 87.

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

يعمل هذا النمط بجعل constructor خاصًا، مما يمنع direct instantiation. وبدلًا من ذلك، تتحكم دالة static في الوصول إلى instance الوحيدة:

public class DatabaseConnection {
    private static DatabaseConnection instance;
    
    // المنشئ الخاص يمنع الإنشاء المباشر
    private DatabaseConnection() {
        System.out.println("Connection created");
    }
    
    // نقطة وصول عالمية
    public static DatabaseConnection getInstance() {
        if (instance == null) {
            instance = new DatabaseConnection();
        }
        return instance;
    }
    
    public void query(String sql) {
        System.out.println("Executing: " + sql);
    }
}

كل استدعاء للدالة getInstance() يعيد الكائن نفسه. يتم إنشاء instance فقط عند طلبه لأول مرة. يُسمّى ذلك lazy initialization:

DatabaseConnection db1 = DatabaseConnection.getInstance();
DatabaseConnection db2 = DatabaseConnection.getInstance();

System.out.println(db1 == db2);  // true - same instance

المكوّنات الأساسية لـ Singleton هي: حقل private static يحتفظ بـ instance، وconstructor من النوع private، وmethod من النوع public static تُعيد instance. يضمن هذا المزيج أنك تحصل دائمًا على object نفسه، بغضّ النظر عن عدد المرات التي تطلب فيها object.

challenge icon

التحدي

سهل

لنَبْنِ مدير إعدادات لتطبيق باستخدام نمط Singleton! سيضمن مدير الإعدادات لديك أن تشارك جميع أجزاء تطبيقك الإعدادات نفسها، بغضّ النظر عن عدد مرات طلبها access.

ستنظّم شيفرتك عبر ملفين:

  • AppConfig.java: أنشئ فئة Singleton تدير إعدادات تكوين التطبيق. يجب أن تحتوي AppConfig لديك على:

    حقل static خاص للاحتفاظ بالـ instance الوحيد.

    حقل String خاص باسم appName وحقل int خاص باسم maxUsers.

    constructor خاص يهيّئ appName إلى "MyApplication" وmaxUsers إلى 100، ثم يطبع AppConfig initialized.

    دالة static عامة getInstance() تنشئ الـ instance فقط إذا لم يكن موجودًا بعد (lazy initialization)، ثم تعيده.

    دالة setAppName(String name) تحدّث اسم التطبيق.

    دالة setMaxUsers(int max) تحدّث الحد الأقصى للمستخدمين.

    دالة displaySettings() تطبع App: [appName], Max Users: [maxUsers].

  • Main.java: أثبت أن Singleton يعمل بصورة صحيحة! ستتلقى inputين: اسم تطبيق جديد (String) وقيمة جديدة للحد الأقصى للمستخدمين (عدد صحيح).

    أولًا، احصل على instance من AppConfig وخزّنه في متغير باسم config1. استدعِ displaySettings() لعرض القيم الافتراضية.

    ثم حدّث الإعدادات باستخدام قيم input الخاصة بك، وذلك باستدعاء setAppName وsetMaxUsers على config1.

    احصل على instance آخر وخزّنه في config2. استدعِ displaySettings() على config2 لإثبات أنه يعكس التغييرات التي أُجريت من خلال config1.

    أخيرًا، اطبع ما إذا كان كلا المرجعين يشيران إلى الكائن نفسه: Same instance: [true/false]، وذلك بمقارنة config1 == config2.

ستتلقى inputين بالترتيب: اسم التطبيق الجديد (String) والحد الأقصى الجديد للمستخدمين (عدد صحيح).

يوضح هذا التحدي الفائدة الأساسية من نمط Singleton: بغضّ النظر عن عدد مرات طلبك للإعدادات، ستحصل دائمًا على الـ instance نفسه بالحالة المشتركة نفسها!

جرّب بنفسك

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // قراءة المدخلات
        String newAppName = scanner.nextLine();
        int newMaxUsers = scanner.nextInt();
        
        // TODO: الحصول على أول مثيل من AppConfig وتخزينه في config1
        
        // TODO: استدعاء displaySettings() على config1 لعرض القيم الافتراضية
        
        // TODO: تحديث الإعدادات باستخدام setAppName و setMaxUsers على config1
        
        // TODO: الحصول على مثيل آخر وتخزينه في config2
        
        // TODO: استدعاء displaySettings() على config2 لإثبات مشاركة التغييرات
        
        // TODO: طباعة ما إذا كان كلا المرجعين يشيران إلى الكائن نفسه:
        // "Same instance: [true/false]" using config1 == config2
    }
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البرمجة كائنية التوجه

تدرّب بنفسك: مترجم Java عبر الإنترنت