תבנית Iterator
חלק מהיחידה תכנות מונחה עצמים במסלול ה-C של Coddy. שיעור 56 מתוך 61.
תבנית האיטרטור מספקת דרך לגשת ברצף לאיברים של אוסף בלי לחשוף את המבנה הפנימי שלו. במקום לתת למשתמשים גישה ישירה למערך, נותנים להם אובייקט שיודע לעבור על הנתונים, איבר אחד בכל פעם.
איטרטור זקוק בדרך כלל לשני פרטי מידע: הפניה לאוסף והמיקום הנוכחי. ב־C, ניצור מבנה כדי לאחסן את המצב הזה:
typedef struct {
int* data; // מצביע למערך
int size; // מספר האיברים הכולל
int current; // המיקום הנוכחי
} IntIterator;האיטרטור חושף שתי פונקציות מרכזיות. has_next() בודקת אם יש עוד איברים לקרוא, ו-next() מחזירה את האיבר הנוכחי ומקדמת את המיקום:
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));
}הקוד שקורא לפונקציה אף פעם לא צריך לדעת ש־numbers הוא מערך או איך פועל האינדוקס. ההפשטה הזאת מקלה על שינוי מבנה הנתונים הבסיסי בהמשך, ממערך לרשימה מקושרת, למשל, בלי לשנות את הקוד שמשתמש באיטרטור.
אתגר
קלבואו נבנה איטרטור NumberList: הפשטה נקייה שמאפשרת לך לעבור על אוסף של מספרים שלמים בלי לחשוף את מבנה המערך שמתחתיו.
תארגן את הקוד שלך בשלושה קבצים:
iterator.h: הגדר מבנהIntIteratorשמכיל מצביע למערך של מספרים שלמים, את הגודל הכולל של האוסף ואת המיקום הנוכחי. הכרז על שלוש פונקציות:create_iterator(מקבלת מצביע למערך ואת הגודל, ומחזירה איטרטור מאותחל),has_next(בודקת אם נותרו איברים נוספים) ו-next(מחזירה את האיבר הנוכחי ומקדמת את המיקום). אל תשכח guards למניעת הכללה כפולה!iterator.c: ממש את פונקציות האיטרטור שלך. הפונקציהcreate_iteratorצריכה להחזירIntIteratorלפי ערך, כשהמיקום הנוכחי מוגדר ל-0. הפונקציהhas_nextמחזירה 1 אם יש איברים נוספים לקריאה, ואחרת 0. הפונקציהnextמחזירה את האיבר במיקום הנוכחי ואז מקדמת את המיקום.main.c: קרא את מספר האיברים, ואז קרא כל ערך של מספר שלם לתוך מערך. צור איטרטור עבור המערך הזה, ואז השתמש בלולאת while עםhas_nextו-nextכדי לעבור על האיברים ולהדפיס כל אחד בשורה משלו.
התוכנית שלך תקבל:
- את מספר האיברים במערך
- כל ערך של מספר שלם בשורה נפרדת
השתמש בתבנית האיטרטור כדי להדפיס את כל האיברים: אל תיגש ישירות למערך באמצעות אינדקסים בלולאת המעבר!
דוגמת פלט כשהקלטים הם 4, ואז 10, 20, 30, 40:
10
20
30
40דוגמת פלט כשהקלטים הם 3, ואז -5, 0, 100:
-5
0
100דוגמת פלט כשהקלטים הם 1, ואז 42:
42האיטרטור מסתיר את אופן אחסון הנתונים. הלולאה הראשית שלך פשוט שואלת "האם יש עוד?" ו"תן לי את הבא" בלי לדעת דבר על אינדקסים של מערך או על מבנה הזיכרון.
נסו בעצמכם
#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: צרו איטרטור עבור המערך
// TODO: השתמשו בלולאת while עם has_next ו-next כדי לעבור על המערך
// והדפיסו כל איבר בשורה נפרדת
// אל תשתמשו בגישה ישירה לאיברי המערך באמצעות אינדקס בלולאת המעבר!
return 0;
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
4כימוס
המושג של מצביעים אטומיםהגדרת מבנים אטומיםפונקציות Get ו-Setאימות ב-Settersסיכום: הקופסה הסודית2אובייקטים ומתודות
מבנים כאובייקטיםמצביע 'Self'נכונות constמצביע לעומת ערךמתודות עזרחזרה: מנהל נקודות5פרויקט: חשבון בנק פשוט
הגדרת הפרויקטמימוש החשבוןתרגלו בעצמכם: קומפיילר C אונליין