Menu
Coddy logo textTech

מימוש ממשקים

חלק מהיחידה תכנות מונחה עצמים במסלול ה-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 מנותקת לחלוטין ממימוש הרישום ביומן. אפשר להחליף רושמי יומן בחופשיות בלי לשנות אף אחד מהלוגיקה המרכזית: זה הכוח של תכנות לממשק.

challenge icon

אתגר

קל

בואו נבנה מערכת INotifier שמדגימה כיצד מימושים שונים יכולים למלא את אותו חוזה ממשק. תיצרו מתריעים קונקרטיים, EmailNotifier ו־SMSNotifier, ששניהם תואמים לממשק משותף אך מפיקים פלטים שונים.

תארגנו את הקוד בשלושה קבצים:

  • notifier.h: הגדירו כאן את הממשק. צרו טיפוס של מצביע לפונקציה בשם NotifyFunc שמקבל הודעת const char* ואינו מחזיר דבר. לאחר מכן הגדירו מבנה INotifier שמכיל רק מצביע לפונקציה notify מטיפוס זה. הכריזו גם על שתי פונקציות בנאי: create_email_notifier ו־create_sms_notifier, שכל אחת מהן מחזירה ערך מסוג INotifier.
  • notifier.c: ממשו כאן את פונקציות ההתראה הקונקרטיות ואת פונקציות הבנאי. צרו:
    • email_notify: מדפיסה את ההודעה בתבנית: [EMAIL] message
    • sms_notify: מדפיסה את ההודעה בתבנית: [SMS] message
    • create_email_notifier: מחזירה INotifier שמחובר אל email_notify
    • create_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;
}
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר C אונליין