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

الـ Getters والـ Setters

جزء من قسم Object Oriented Programming في رحلة C على Coddy — الدرس 19 من 61.

مع المؤشرات غير الشفافة (opaque pointers)، تكون أعضاء الـ struct مخفية عن الكود الخارجي. ولكن إذا لم يتمكن الكود الخارجي من الوصول إلى البيانات مباشرة، فكيف نقوم بقراءتها أو تعديلها؟ الإجابة هي دوال الـ getter والـ setter — وهي واجهات عامة توفر وصولاً متحكماً فيه للبيانات الخاصة.

يقوم الـ getter بإرجاع قيمة عضو مخفي:

// counter.h
int counter_get_value(const Counter *c);

// counter.c
int counter_get_value(const Counter *c) {
    return c->value;
}

يقوم الـ setter بتعديل عضو مخفي:

// counter.h
void counter_set_value(Counter *c, int new_value);

// counter.c
void counter_set_value(Counter *c, int new_value) {
    c->value = new_value;
}

لاحظ اصطلاح التسمية: أضف اسم النوع كبادئة للوظائف (counter_) لتجنب التعارضات وجعل واجهة برمجة التطبيقات (API) واضحة. تستخدم دوال الجلب (Getters) مؤشرات const لأنها لا تعدل الكائن.

الآن يمكن للكود الخارجي التفاعل مع البيانات المخفية بأمان:

// main.c
Counter *c = create_counter(10);
printf("%d\n", counter_get_value(c));  // 10
counter_set_value(c, 25);
printf("%d\n", counter_get_value(c));  // 25

يوفر لك هذا النمط تحكماً كاملاً في كيفية الوصول إلى البيانات — وهو أساس سنبني عليه في الدرس القادم عندما نضيف منطق التحقق (validation logic) إلى الـ setters.

challenge icon

التحدي

سهل

لنقم ببناء وحدة Score تستخدم نمط المؤشر غير الشفاف (opaque pointer pattern) مع دوال الجلب (getter) والتعيين (setter). ستقوم بإنشاء متتبع نقاط مخفي حيث لا يمكن للكود الخارجي التفاعل مع البيانات إلا من خلال الواجهة العامة التي توفرها.

ستقوم بإنشاء ثلاثة ملفات:

  • score.h: واجهتك العامة. قم بالتصريح عن نوع Score غير شفاف باستخدام تصريح مسبق (forward declaration) (بدون جسم الـ struct!). قم بالتصريح عن هذه الدوال:
    • create_score — تأخذ عدداً صحيحاً للنقاط الأولية وتُرجع مؤشراً من نوع Score
    • free_score — تأخذ مؤشراً من نوع Score وتقوم بتحرير الذاكرة
    • score_get_points — دالة جلب (getter) تأخذ const Score * وتُرجع النقاط الحالية
    • score_set_points — دالة تعيين (setter) تأخذ Score * وعدداً صحيحاً، وتقوم بتحديث قيمة النقاط
    استخدم حواجز التضمين (include guards) مع الرمز SCORE_H.
  • score.c: قم بتعريف الـ struct Score الفعلي مع عضو مخفي واحد: int points. قم بتنفيذ الدوال الأربع جميعها. يجب أن تُرجع دالة الجلب القيمة المخفية، ويجب أن تقوم دالة التعيين بتحديثها. تذكر أن دوال الجلب تستخدم مؤشرات const لأنها لا تعدل الكائن.
  • main.c: قم باستعراض وحدتك من خلال إنشاء نتيجة (score)، وقراءة قيمتها، وتعديلها من خلال دالة التعيين، وقراءتها مرة أخرى.

ستتلقى مدخلين: النقاط الأولية (عدد صحيح) و قيمة النقاط الجديدة (عدد صحيح) لتعيينها.

في ملفك الرئيسي، قم بإنشاء Score بالنقاط الأولية، واطبع القيمة الحالية باستخدام دالة الجلب، ثم قم بتحديثها باستخدام دالة التعيين بالقيمة الجديدة، واطبع القيمة المحدثة، ثم قم بتحرير الـ score واطبع تأكيداً.

اطبع المخرجات بهذا التنسيق:

Initial: {points}
Updated: {points}
Freed

على سبيل المثال، مع المدخلات 100 و 250، ستكون المخرجات:

Initial: 100
Updated: 250
Freed

لاحظ كيف لا يمكن لـ main.c الوصول إلى points مباشرة — يجب أن يمر عبر دوال الجلب والتعيين الخاصة بك. هذا هو التغليف (encapsulation) في أبهى صوره: أنت تتحكم بالضبط في كيفية قراءة البيانات المخفية وتعديلها.

ورقة مرجعية

مع المؤشرات غير الشفافة (opaque pointers)، يتم إخفاء أعضاء الهيكل (struct members) عن الكود الخارجي. للوصول إلى هذه البيانات الخاصة أو تعديلها، استخدم دوال getter و setter.

تعيد دالة الـ getter قيمة العضو المخفي وتستخدم مؤشر const لأنها لا تعدل الكائن:

// counter.h
int counter_get_value(const Counter *c);

// counter.c
int counter_get_value(const Counter *c) {
    return c->value;
}

تقوم دالة الـ setter بتعديل عضو مخفي:

// counter.h
void counter_set_value(Counter *c, int new_value);

// counter.c
void counter_set_value(Counter *c, int new_value) {
    c->value = new_value;
}

استخدم اصطلاح تسمية مع اسم النوع كبادئة (counter_) لتجنب التعارضات وتوضيح واجهة برمجة التطبيقات (API).

يتفاعل الكود الخارجي مع البيانات المخفية من خلال هذه الدوال:

// main.c
Counter *c = create_counter(10);
printf("%d\n", counter_get_value(c));  // 10
counter_set_value(c, 25);
printf("%d\n", counter_get_value(c));  // 25

جرّب بنفسك

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

int main() {
    int initial_points, new_points;
    scanf("%d", &initial_points);
    scanf("%d", &new_points);
    
    // TODO: قم بإنشاء Score باستخدام initial_points
    
    // TODO: اطبع القيمة الأولية باستخدام الـ getter
    // التنسيق: "Initial: {points}"
    
    // TODO: قم بتحديث النتيجة باستخدام الـ setter مع new_points
    
    // TODO: اطبع القيمة المحدثة باستخدام الـ getter
    // التنسيق: "Updated: {points}"
    
    // TODO: قم بتحرير الـ score واطبع "Freed"
    
    return 0;
}
quiz iconاختبر نفسك

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

جميع دروس Object Oriented Programming