نمط Iterator
جزء من قسم Object Oriented Programming في رحلة C على Coddy — الدرس 56 من 61.
يوفر نمط المكرر (Iterator pattern) طريقة للوصول إلى عناصر مجموعة ما بشكل تسلسلي دون الكشف عن بنيتها الأساسية. فبدلاً من منح المستخدمين وصولاً مباشراً إلى مصفوفة، فإنك تمنحهم كائناً يعرف كيفية التنقل عبر البيانات عنصراً تلو الآخر.
يحتاج المكرر (iterator) عادةً إلى معلومتين: مرجع للمجموعة والموضع الحالي. في لغة C، نقوم بإنشاء هيكل (struct) للاحتفاظ بهذه الحالة:
typedef struct {
int* data; // مؤشر إلى المصفوفة
int size; // العدد الإجمالي للعناصر
int current; // الموضع الحالي
} IntIterator;يوفر المكرر (iterator) وظيفتين أساسيتين. تتحقق has_next() مما إذا كان هناك المزيد من العناصر للقراءة، وتعيد next() العنصر الحالي وتنتقل إلى الموضع التالي:
int has_next(IntIterator* it) {
return it->current < it->size;
}
int next(IntIterator* it) {
return it->data[it->current++];
}يبدو استخدام المكرر (iterator) منظماً ويخفي تفاصيل المصفوفة:
IntIterator it = create_iterator(numbers, 5);
while (has_next(&it)) {
printf("%d\n", next(&it));
}لا يحتاج المستدعي أبدًا إلى معرفة أن numbers عبارة عن مصفوفة أو كيف تعمل عملية الفهرسة. هذا التجريد يجعل من السهل تغيير هيكل البيانات الأساسي لاحقًا — من مصفوفة إلى قائمة مرتبطة، على سبيل المثال — دون تغيير الكود الذي يستخدم المكرر (iterator).
التحدي
سهللنقم ببناء مكرر (iterator) لـ NumberList — وهو تجريد نظيف يتيح لك التنقل عبر مجموعة من الأعداد الصحيحة دون الكشف عن بنية المصفوفة الأساسية.
ستقوم بتنظيم الكود الخاص بك عبر ثلاثة ملفات:
iterator.h: قم بتعريف هيكل (struct) باسمIntIteratorيحتوي على مؤشر لمصفوفة أعداد صحيحة، والحجم الإجمالي للمجموعة، والموقع الحالي. قم بالتصريح عن ثلاث دوال:create_iterator(تأخذ مؤشر مصفوفة وحجمها، وتعيد مكررًا مهيأً)، وhas_next(تتحقق مما إذا كانت هناك عناصر متبقية)، وnext(تعيد العنصر الحالي وتقدم الموقع). لا تنسَ حواجز التضمين (include guards)!iterator.c: قم بتنفيذ دوال المكرر الخاصة بك. يجب أن تعيد الدالةcreate_iteratorقيمة من نوعIntIteratorمع ضبط الموقع الحالي على 0. تعيد الدالةhas_nextالقيمة 1 إذا كان هناك المزيد من العناصر للقراءة، و 0 بخلاف ذلك. تعيد الدالةnextالعنصر الموجود في الموقع الحالي ثم تزيد الموقع.main.c: اقرأ عدد العناصر، ثم اقرأ كل قيمة عدد صحيح في مصفوفة. أنشئ مكررًا لهذه المصفوفة، ثم استخدم حلقة while معhas_nextوnextللتنقل وطباعة كل عنصر في سطر منفصل.
سيتلقى برنامجك:
- عدد العناصر في المصفوفة
- كل قيمة عدد صحيح في سطر منفصل
استخدم نمط المكرر (iterator pattern) لطباعة جميع العناصر — لا تستخدم فهرسة المصفوفة المباشرة في حلقة التنقل الخاصة بك!
مثال على المخرجات عندما تكون المدخلات 4، ثم 10، 20، 30، 40:
10
20
30
40مثال على المخرجات عندما تكون المدخلات 3، ثم -5، 0، 100:
-5
0
100مثال على المخرجات عندما تكون المدخلات 1، ثم 42:
42يقوم المكرر بإخفاء كيفية تخزين البيانات — تسأل الحلقة الرئيسية ببساطة "هل هناك المزيد؟" و "أعطني العنصر التالي" دون معرفة أي شيء عن فهارس المصفوفة أو تخطيط الذاكرة.
ورقة مرجعية
يوفر نمط المكرر (Iterator pattern) طريقة للوصول إلى عناصر مجموعة ما بشكل تسلسلي دون الكشف عن هيكلها الأساسي.
يحتوي هيكل (struct) المكرر على مرجع المجموعة، وحجمها، وموقعها الحالي:
typedef struct {
int* data; // مؤشر إلى المصفوفة
int size; // إجمالي عدد العناصر
int current; // الموقع الحالي
} IntIterator;يكشف المكرر عن وظيفتين أساسيتين:
int has_next(IntIterator* it) {
return it->current < it->size;
}
int next(IntIterator* it) {
return it->data[it->current++];
}يؤدي استخدام المكرر إلى إخفاء تفاصيل تنفيذ المصفوفة:
IntIterator it = create_iterator(numbers, 5);
while (has_next(&it)) {
printf("%d\n", next(&it));
}يسمح هذا التجريد بتغيير هيكل البيانات الأساسي دون تعديل كود العميل.
جرّب بنفسك
#include <stdio.h>
#include "iterator.h"
int main() {
int n;
scanf("%d", &n);
int arr[n];
// TODO: اقرأ n من القيم الصحيحة في المصفوفة
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
// TODO: أنشئ iterator للمصفوفة
// TODO: استخدم حلقة while مع `has_next` و `next` للمرور عبر العناصر
// واطبع كل عنصر في سطر منفصل
// لا تستخدم فهرسة المصفوفة المباشرة في حلقة المرور الخاصة بك!
return 0;
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات البرمجة التركيبية
ملفات الترويسةحواجز التضمينملفات المصدرالدوال الساكنةمراجعة: آلة حاسبة تركيبية4التغليف (Encapsulation)
مفهوم الـ Opaque Pointersتعريف الـ Opaque Structsالـ Getters والـ Settersالتحقق من البيانات في الـ Settersملخص: الصندوق السري2الكائنات والأساليب
الـ Structs ككائناتمؤشر 'Self'صحة استخدام Constالمؤشر مقابل القيمةالأساليب المساعدةملخص: Point Manager5مشروع: حساب بنكي بسيط
إعداد المشروعتنفيذ الحساب3دورة حياة الكائن
نمط المنشئ (Constructor Pattern)نمط الهادم (Destructor Pattern)تهيئة الـ Stackالنسخ العميق (Deep Copy)مراجعة: String Wrapper6الوراثة عبر التركيب
تضمين الـ Structقاعدة العضو الأولالوصول إلى أعضاء الأبعملية الـ Upcastingمراجعة: هرمية الأشكال9مشروع: رسّام الأشكال
نظرة عامة على المشروعتنفيذ الدائرة