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

نمط Singleton

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

أحيانًا تحتاج إلى instance واحد فقط من كائن طوال برنامجك بالكامل: مدير إعدادات، أو نظام تسجيل، أو اتصال بقاعدة بيانات. يضمن نمط Singleton وجود instance واحدة only ويوفر نقطة وصول عامة إليها.

في لغة C، نُنفّذ ذلك باستخدام متغيّر static داخل ملف مصدر. تذكّر أن static على مستوى الملف يعني أن المتغيّر خاص بذلك الملف ويستمر طوال عمر البرنامج. وبدمجه مع دالة getter، ينشئ ذلك Singleton الخاص بنا:

// config.c
#include "config.h"
#include <stdlib.h>

struct Config {
    int max_connections;
    int timeout;
};

static Config* instance = NULL;

Config* get_config(void) {
    if (instance == NULL) {
        instance = malloc(sizeof(Config));
        instance->max_connections = 100;
        instance->timeout = 30;
    }
    return instance;
}

يحدث السحر في get_config(). ينشئ call first instance ويهيّئها. كل call لاحق يعيد same pointer.

تضمن الكلمة المفتاحية static أن تحتفظ instance بقيمتها بين استدعاءات الدوال وأن تظل مخفية عن الملفات الأخرى.

من ملف الترويسة، لا يرى المستخدمون سوى دالة getter. ولا يمكنهم الوصول إلى المتغير static أو تعديله مباشرةً. وبغضّ النظر عن عدد المرات أو المكان الذي تستدعي منه get_config()، ستحصل دائمًا على الكائن نفسه.

challenge icon

التحدي

سهل

لنبنِ وحدة Settings تدير إعدادات التطبيق على مستوى التطبيق باستخدام نمط Singleton. بغض النظر عن عدد المرات التي يطلب فيها الكود الإعدادات، يجب أن يتلقى دائمًا نفس instance تمامًا.

ستنظم الكود عبر ثلاثة ملفات:

  • settings.h: Declare نوع Settings opaque باستخدام forward declaration (يبقى جسم البنية مخفيًا). Declare دالة get_settings التي returns مؤشرًا إلى singleton instance، بالإضافة إلى دوال getter وsetter لقيمتي إعداد: volume (عدد صحيح) وbrightness (عدد صحيح). تُعد Include guards ضرورية هنا.
  • settings.c: هنا يحدث السحر. Define بنية Settings الفعلية مع volume وbrightness fields. Create متغير مؤشر static للاحتفاظ بـ single instance (تمت تهيئته إلى NULL). Implement get_settings بحيث يقوم first Call بتخصيص instance وتهيئته بالقيم الافتراضية (volume: 50، brightness: 75)، بينما تقوم calls اللاحقة ببساطة بإرجاع existing instance. Implement دوال getter وsetter للوصول إلى الحقول المخفية وتعديلها.
  • main.c: Demonstrate أن Singleton يعمل بشكل صحيح. اقرأ عددين صحيحين يمثلان قيمتي volume وbrightness الجديدتين. Call get_settings twice، مع تخزين النتائج في two different pointer variables. استخدم first pointer لتحديث volume وbrightness باستخدام قيم input. ثم استخدم second pointer لاسترجاع كلتا القيمتين وطباعتهما. إذا كان Singleton يعمل، فستكون التغييرات التي أُجريت من خلال مؤشر واحد مرئية من خلال المؤشر الآخر.

سيتلقى برنامجك مدخلين:

  1. قيمة volume الجديدة
  2. قيمة brightness الجديدة

اطبع volume وbrightness في سطرين منفصلين بعد تعديلهِما من خلال مؤشر واحد وقراءتهِما من خلال مؤشر آخر.

مثال على المخرجات عندما تكون المدخلات 80 و100:

80
100

مثال على المخرجات عندما تكون المدخلات 25 و60:

25
60

مثال على المخرجات عندما تكون المدخلات 0 و50:

0
50

الفكرة الأساسية هي أن both pointers يشيران إلى نفس الكائن في الذاكرة: وهذا هو جوهر نمط Singleton. يضمن المتغير static داخل ملفك المصدر وجود only one instance على الإطلاق، ويستمر طوال lifetime البرنامج بالكامل.

جرّب بنفسك

#include <stdio.h>
#include "settings.h"

int main() {
    int new_volume, new_brightness;
    scanf("%d", &new_volume);
    scanf("%d", &new_brightness);
    
    // TODO: استدعِ get_settings مرتين وخزّن في متغيري مؤشر مختلفين
    
    
    // TODO: استخدم المؤشر الأول لتحديث volume و brightness بقيم الإدخال
    
    
    // TODO: استخدم المؤشر الثاني لاسترجاع وطباعة volume و brightness
    // (هذا يوضح أن كلا المؤشرين يشيران إلى نفس مثيل singleton)
    
    
    return 0;
}
quiz iconاختبر نفسك

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

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

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