نمط Iterator
جزء من قسم البرمجة كائنية التوجه في رحلة C على Coddy. الدرس 56 من 61.
يوفّر نمط Iterator طريقة للوصول إلى عناصر collection بالتتابع دون كشف بنيتها الأساسية. وبدلاً من منح المستخدمين وصولاً direct إلى array، تمنحهم كائناً يعرف كيفية التنقّل عبر data بمقدار element واحد في كل مرة.
يحتاج iterator عادةً إلى قطعتين من المعلومات: مرجع إلى collection وposition الحالية. في C، ننشئ struct للاحتفاظ بهذه الحالة:
typedef struct {
int* data; // مؤشر إلى المصفوفة
int size; // العدد الإجمالي للعناصر
int current; // الموضع الحالي
} IntIterator;يكشف المكرّر عن functions رئيسيتين. تتحقق has_next() مما إذا كانت هناك more من elements لقراءتها، وتُرجع next() العنصر current وتُقدّم الموضع:
int has_next(IntIterator* it) {
return it->current < it->size;
}
int next(IntIterator* it) {
return it->data[it->current++];
}يبدو استخدام iterator أنيقًا ويخفي تفاصيل array:
IntIterator it = create_iterator(numbers, 5);
while (has_next(&it)) {
printf("%d\n", next(&it));
}لا يحتاج المستدعي أبدًا إلى معرفة أن numbers هي array أو كيفية عمل indexing. يجعل هذا التجريد من السهل تغيير بنية البيانات الأساسية لاحقًا، من array إلى قائمة مرتبطة، على سبيل المثال، من دون تغيير الكود الذي يستخدم iterator.
التحدي
سهللنَبْنِ مُكرِّرًا لـ NumberList: تجريدًا نظيفًا يتيح لك اجتياز مجموعة من الأعداد الصحيحة دون كشف بنية array الأساسية.
ستنظّم شيفرتك عبر ثلاثة ملفات:
iterator.h: عرّف بنيةIntIteratorالتي تحتوي على مؤشر إلىarrayمن الأعداد الصحيحة، والحجم الإجمالي للمجموعة، والموضع الحالي. أعلن عن ثلاثfunctions:create_iterator(تأخذ مؤشرarrayوالحجم، وتعيد مُكرِّرًاinitializedًا)، وhas_next(تتحقق مما إذا كانت هناكelementsإضافية متبقية)، وnext(تعيدelementالحالي وتُقدِّم الموضع). لا تنسَ حواجزinclude!iterator.c: نفّذfunctionsالمخصّصة للمُكرِّر. يجب أن تعيدcreate_iteratorقيمة من النوعIntIterator، مع ضبط الموضع الحالي على 0. تعيدhas_nextالقيمة 1 إذا كانت هناكelementsإضافية للقراءة، و0otherwise. تعيدnextالـelementالموجود عند الموضع الحالي، ثم تزيد الموضع.main.c: اقرأnumberالـelements، ثم اقرأ قيمة كل عدد صحيح إلىarray. أنشئ مُكرِّرًا لهذا الـarray، ثم استخدمwhileloopمعhas_nextوnextلاجتياز كلelementوطباعته في سطر خاص به.
سيستقبل برنامجك:
- عدد
elementsفي الـarray - كل قيمة عدد صحيح في سطر منفصل
استخدم نمط المُكرِّر لطباعة جميع elements: لا تستخدم direct array indexing في loop الاجتياز!
ناتج مثالي عندما تكون المدخلات هي 4، ثم 10، و20، و30، و40:
10
20
30
40ناتج مثالي عندما تكون المدخلات هي 3، ثم -5، و0، و100:
-5
0
100ناتج مثالي عندما تكون المدخلات هي 1، ثم 42:
42يخفي المُكرِّر كيفية تخزين data. يطلب main loop ببساطة "is there more?" و"give me the next one" دون معرفة أي شيء عن مؤشرات الـarray أو تخطيط الذاكرة.
جرّب بنفسك
#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;
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
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مشروع: رسّام الأشكال
نظرة عامة على المشروعتنفيذ الدائرةتنفيذ المستطيلاستخدام تعدد الأشكالحاوية الأشكالتدرّب بنفسك: مترجم C عبر الإنترنت