インターフェースの実装
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 関数は、ロギングの実装から完全に切り離されています。中核となるロジックを変更せずにロガーを自由に交換できます。これがインターフェースに対してプログラミングすることの力です。
チャレンジ
簡単INotifierシステムを構築して、異なる実装が同じインターフェース契約をどのように満たせるかを示しましょう。共通のインターフェースに準拠しながら異なる出力を生成する、具体的な通知機能であるEmailNotifierとSMSNotifierを作成します。
コードを3つのファイルに分けて整理します。
notifier.h:ここでインターフェースをDefineします。const char*型のmessageを受け取り、何も返さない関数ポインター型NotifyFuncをCreateします。次に、この型のnotify関数ポインターだけを含むINotifier構造体をDefineします。また、それぞれ値としてINotifierを返す2つのconstructor関数、create_email_notifierとcreate_sms_notifierもDeclareします。notifier.c:ここで具体的なnotification関数とconstructorをImplementします。次をCreateします。email_notify:次の形式でmessageを出力します:[EMAIL] messagesms_notify:次の形式でmessageを出力します:[SMS] messagecreate_email_notifier:email_notifyに接続されたINotifierを返しますcreate_sms_notifier:sms_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 3pmtypeが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;
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Cオンラインコンパイラ