Menu
Coddy logo textTech

イベントシステム

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

challenge icon

チャレンジ

簡単

Notification Systemを構築しましょう。これは、複数のハンドラーがイベントを購読し、イベントが発火したときに応答できるイベント駆動アーキテクチャです。このパターンは、リアクティブプログラミングやGUIフレームワークの基盤となります。

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

  • event.hconst char*型のmessageを受け取るHandler関数ポインタ型をDefineします。最大5個のハンドラーのarrayと、登録済みハンドラーのcountを保持するEvent構造体をCreateします。イベントを初期化し、ハンドラーを購読し、すべての購読者にNotifyするためにイベントをfireする関数を宣言します。
  • event.c:イベントシステムをImplementします。
    • init_event:Eventポインタを受け取り、ハンドラーのcountを0に設定します
    • subscribe:EventポインタとHandlerを受け取り、空きがある場合(countが5未満の場合)にハンドラーをarrayへ追加し、countをインクリメントします
    • fire:Eventポインタとmessage文字列を受け取り、登録された各ハンドラーを、購読されたorderでそのmessageとともにcallsします
  • main.c:イベントに対してそれぞれ異なる方法で応答する3つのhandler関数をCreateします。
    • logger:messageに続けて[LOG] をPrintsします
    • alert:messageに続けて[ALERT] をPrintsします
    • counter:static変数を使用してcallsされた回数をcountし、その後、現在のcountをXとして[COUNT] XをPrintsします
    購読するハンドラーの数(1、2、または3)を示すnumberをReadします。その数のハンドラーをorderどおりに購読します。最初にlogger、次にalert(2以上の場合)、最後にcounter(3の場合)を購読します。message文字列をReadし、そのmessageでイベントをfireします。

プログラムは次の入力を受け取ります。

  1. 購読するハンドラーの数(1、2、または3)
  2. ブロードキャストするmessage

入力が3System startedの場合の出力例:

[LOG] System started
[ALERT] System started
[COUNT] 1

入力が2Warning detectedの場合の出力例:

[LOG] Warning detected
[ALERT] Warning detected

入力が1Helloの場合の出力例:

[LOG] Hello

これは、関数ポインタによるポリモーフィズムを示しています。同じfireのcallsであっても、どのハンドラーが購読されているかによって、まったく異なる動作がトリガーされます。各ハンドラーは同じイベントに対して独自の方法で応答し、イベント駆動設計の疎結合な性質を示しています。

自分で試してみよう

#include <stdio.h>
#include <string.h>
#include "event.h"

// TODO: logger ハンドラを実装する
// "[LOG] " に続いてメッセージを出力する
void logger(const char* message) {
    // TODO: 実装する
}

// TODO: alert ハンドラを実装する
// "[ALERT] " に続いてメッセージを出力する
void alert(const char* message) {
    // TODO: 実装する
}

// TODO: counter ハンドラを実装する
// 呼び出し回数を数えるために static 変数を使用する
// "[COUNT] X" を出力する(X は現在のカウント)
void counter(const char* message) {
    // TODO: static 変数を使って実装する
}

int main() {
    // 購読するハンドラの数を読み取る
    int num_handlers;
    scanf("%d", &num_handlers);
    getchar(); // 改行を消費する
    
    // メッセージを読み取る
    char message[256];
    fgets(message, sizeof(message), stdin);
    message[strcspn(message, "\n")] = '\0'; // 改行を削除
    
    // TODO: Eventを作成して初期化する
    
    // TODO: num_handlersに基づいてハンドラを登録する
    // 1ハンドラ: logger
    // 2ハンドラ: logger, alert
    // 3ハンドラ: logger, alert, counter
    
    // TODO: メッセージでイベントを発火する
    
    return 0;
}
quiz icon腕試し

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

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

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