מימוש ממשקים
חלק מהיחידה תכנות מונחה עצמים במסלול ה-C של Coddy. שיעור 41 מתוך 61.
עכשיו, כשאתה מבין מהו ממשק — מבנה שמכיל רק מצביעים לפונקציות — הגיע הזמן ליצור מימושים קונקרטיים שמקיימים את החוזה הזה.
ניזכר בממשק ILogger שלנו מהשיעור הקודם:
typedef void (*LogFunc)(const char* message);
typedef struct {
LogFunc log;
} ILogger;כדי לממש את הממשק הזה, נכתוב פונקציות ממשיות שתואמות לחתימה של LogFunc, ואז ניצור מופעים של ILogger ונקצה להם את הפונקציות האלה:
void console_log(const char* message) {
printf("[CONSOLE] %s\n", message);
}
void file_log(const char* message) {
printf("[FILE] %s\n", message); // הדמיה של פלט לקובץ
}
ILogger create_console_logger() {
ILogger logger = { console_log };
return logger;
}
ILogger create_file_logger() {
ILogger logger = { file_log };
return logger;
}כל פונקציית "בנאי" מחזירה ILogger עם פונקציה אחרת מחוברת אליה. קוד שמשתמש ביומנים האלה לא צריך לדעת איזו מימוש הוא קיבל:
void do_work(ILogger* logger) {
logger->log("Starting work...");
logger->log("Work complete!");
}
int main() {
ILogger console = create_console_logger();
ILogger file = create_file_logger();
do_work(&console); // משתמש ב-console_log
do_work(&file); // משתמש ב-file_log
return 0;
}הפונקציה do_work מנותקת לחלוטין ממימוש הרישום ביומן. אפשר להחליף רושמי יומן בחופשיות בלי לשנות אף אחד מהלוגיקה המרכזית: זה הכוח של תכנות לממשק.
אתגר
קלבואו נבנה מערכת INotifier שמדגימה כיצד מימושים שונים יכולים למלא את אותו חוזה ממשק. תיצרו מתריעים קונקרטיים, EmailNotifier ו־SMSNotifier, ששניהם תואמים לממשק משותף אך מפיקים פלטים שונים.
תארגנו את הקוד בשלושה קבצים:
notifier.h: הגדירו כאן את הממשק. צרו טיפוס של מצביע לפונקציה בשםNotifyFuncשמקבל הודעתconst char*ואינו מחזיר דבר. לאחר מכן הגדירו מבנהINotifierשמכיל רק מצביע לפונקציהnotifyמטיפוס זה. הכריזו גם על שתי פונקציות בנאי:create_email_notifierו־create_sms_notifier, שכל אחת מהן מחזירה ערך מסוגINotifier.notifier.c: ממשו כאן את פונקציות ההתראה הקונקרטיות ואת פונקציות הבנאי. צרו:email_notify: מדפיסה את ההודעה בתבנית:[EMAIL] messagesms_notify: מדפיסה את ההודעה בתבנית:[SMS] messagecreate_email_notifier: מחזירהINotifierשמחובר אלemail_notifycreate_sms_notifier: מחזירהINotifierשמחובר אלsms_notify
main.c: חברו כאן את כל החלקים. קראו סוג התראה והודעה, צרו את המתריע המתאים באמצעות פונקציות הבנאי ושלחו את ההתראה דרך הממשק.
התוכנית שלכם תקבל שני קלטים: סוג התראה (1 עבור דוא״ל, 2 עבור SMS) והודעה לשליחה.
השתמשו בפונקציות הבנאי כדי ליצור את המתריע המתאים, ואז קראו ל־notify דרך הממשק כדי להציג את ההודעה.
דוגמת פלט כאשר הסוג הוא 1 וההודעה היא Meeting at 3pm:
[EMAIL] Meeting at 3pmדוגמת פלט כאשר הסוג הוא 2 וההודעה היא Your code shipped:
[SMS] Your code shippedהיתרון של התבנית הזאת הוא ש־main.c לא צריך לדעת איך כל מתריע פועל מבפנים. הוא פשוט קורא לפונקציית notify של הממשק, והמימוש המתאים מופעל. זכרו להשתמש בשומרי הכללה בקובץ הכותרת שלכם.
נסו בעצמכם
#include <stdio.h>
#include "notifier.h"
int main() {
int type;
char message[256];
// קרא את סוג ההתראה (1 לאימייל, 2 ל-SMS)
scanf("%d", &type);
getchar(); // צרוך את תו סוף השורה
// קרא את ההודעה
fgets(message, sizeof(message), stdin);
// הסר את תו סוף השורה בסוף ההודעה, אם קיים
int len = 0;
while (message[len] != '\0') len++;
if (len > 0 && message[len-1] == '\n') message[len-1] = '\0';
// TODO: צור את ה-notifier המתאים בהתאם ל-type
// השתמש ב-create_email_notifier() עבור type 1
// השתמש ב-create_sms_notifier() עבור type 2
// TODO: קרא לפונקציה notify דרך הממשק
// notifier.notify(message);
return 0;
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
4כימוס
המושג של מצביעים אטומיםהגדרת מבנים אטומיםפונקציות Get ו-Setאימות ב-Settersסיכום: הקופסה הסודית2אובייקטים ומתודות
מבנים כאובייקטיםמצביע 'Self'נכונות constמצביע לעומת ערךמתודות עזרחזרה: מנהל נקודות5פרויקט: חשבון בנק פשוט
הגדרת הפרויקטמימוש החשבוןתרגלו בעצמכם: קומפיילר C אונליין