Menu
Coddy logo textTech

インターフェースの実装

CoddyのCジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 41/61。

インターフェースとは何か、つまり関数ポインターだけを含む構造体について理解できたので、次はその契約を満たす具体的な実装を作成しましょう。

前のレッスンで学んだ ILogger インターフェースを思い出してください。

typedef void (*LogFunc)(const char* message);

typedef struct {
    LogFunc log;
} ILogger;

この interface を実装するには、LogFunc シグネチャに一致する実際の functions を記述し、それらの functions を割り当てた 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;
}

各「constructor」function は、異なる function が組み込まれた 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システムを構築して、異なる実装が同じインターフェース契約をどのように満たせるかを示しましょう。共通のインターフェースに準拠しながら異なる出力を生成する、具体的な通知機能であるEmailNotifierSMSNotifierを作成します。

コードを3つのファイルに分けて整理します。

  • notifier.h:ここでインターフェースをDefineします。const char*型のmessageを受け取り、何も返さない関数ポインター型NotifyFuncをCreateします。次に、この型のnotify関数ポインターだけを含むINotifier構造体をDefineします。また、それぞれ値としてINotifierを返す2つのconstructor関数、create_email_notifiercreate_sms_notifierもDeclareします。
  • notifier.c:ここで具体的なnotification関数とconstructorをImplementします。次をCreateします。
    • email_notify:次の形式でmessageを出力します:[EMAIL] message
    • sms_notify:次の形式でmessageを出力します:[SMS] message
    • create_email_notifieremail_notifyに接続されたINotifierを返します
    • create_sms_notifiersms_notifyに接続されたINotifierを返します
  • main.c:ここですべてを組み合わせます。notification typeとmessageを読み取り、constructor関数を使用してappropriateなnotifierをCreateし、インターフェースを通じてnotificationを送信します。

プログラムは2つの入力を受け取ります。notification type(emailの場合は1、SMSの場合は2)と、送信するmessageです。

constructor関数を使用してappropriateなnotifierをCreateし、インターフェースを通じてnotifyをCallし、messageを表示します。

typeが1でmessageがMeeting at 3pmの場合の出力例:

[EMAIL] Meeting at 3pm

typeが2でmessageがYour code shippedの場合の出力例:

[SMS] Your code shipped

このパターンの強みは、main.cが各notifierの内部での動作方法を知る必要がないことです。単にインターフェースのnotify関数をCallするだけで、appropriateな実装が実行されます。headerファイルではincludeガードを使用することを忘れないでください。

自分で試してみよう

#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を作成する
    // タイプ1にはcreate_email_notifier()を使用する
    // タイプ2にはcreate_sms_notifier()を使用する
    
    // TODO: インターフェース経由でnotify関数を呼び出す
    // notifier.notify(message);
    
    return 0;
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Cオンラインコンパイラ