C言語講座16回目になります。
今回もC言語によるオブジェクト指向です。
前回からさらに発展させて、フレームワークの考え方を書いてみます。
C言語作るアプリケーションフレームワークを考える

アプリケーションフレームワークとは
フレームワークとはある種のアプリケーションの作り方のパターンを示しているもので、Web系のアプリケーションのフレームワーク
はよく使われています。
実際、フレームワークというとそちらを意識する人が多いと思われます。
Pythonだと、Django、Flask。
PHPだと、CakePHP、Laravel。
Javaだと、Spring、Struts。
Rubyだと、Ruby on rails。
C++は、MFC(Microsoft Foundation Class)。
フレームワークにより違いはありますが、セキュリティ、画面遷移、画面間のデータ連携、入力チェック等を容易にするための仕組みを提供しています。
つまり、ルールに従ってコーディングすれば、画面遷移してくれたり、次の画面にデータが渡ってくれたりして非常に便利です。
しかしアプリケーションの作り方を規定する型であれば、別にWebアプリケーションに限りません。
ということで、今回は、ファイルをデータベースにロードするアプリケーションを考えてみます。
C言語で作る、アプリケーションフレームワーク
ファイルをデータベースのテーブルにロードするアプリケーションを考えてみます。
わざわざプログラムにしなくても、ローディングのツールを使えば簡単な場合も多いですが、ファイルを読み込んで編集しながらテーブルに書き込む場合など、単純にロードできないケースもよくあります。
・ファイルを読み込み
・編集して
・テーブルに書き込む
という処理です。
テーブルへのデータロードなら、1行読み込み、編集した結果をテーブルに書き込むという流れでいけます。
実際には処理速度を考えて、全編集後に一括書き込み等実務上は工夫が必要ですが、今回はフレームワークのイメージをお伝えするために、単純化しました。
オブジェクト指向なので、登場するものを考えます。
【データロードアプリ:フレームワーク】、【ファイル】、【データベース(テーブル)】
テーブル、ファイル、データベースを生成して(ファイルはオープン)、データロードアプリ:フレームワークに渡します。
フレームワークは、ファイルから一行読み出し、編集処理を呼び出し、テーブルに一行書き込みます。
100テーブルロードするとしても、違いがあるのは、テーブル、ファイル、編集処理だけになります。
単純化してしまえば、データベースロードアプリ(対象テーブル、ファイル名、編集処理)と、3つの内容を渡してあげれば、後の処理はまったく変わらないということです。
処理の流れも同一です。
・DB接続、ファイルをオープン(ファイル名だけ違う)
・1行読み込みながら、編集処理(処理だけ違う)して書き込み。
・ファイルエンドになったら、終了。
実際には、1つできたらそれをコピーして作ることが普通にあると思います。
一部を書き直してテストをやっているうちに、コピーした元のプログラムにバグが発覚して、たくさん展開されているから、それまでに開発した対象全部を修正した経験があるかたもいるのではないでしょうか。
フレームワークとして開発した場合は、コピーはしなくてすみます。
実際にコーディングが発生するのは、編集処理部分のみ。
ということで、編集処理を関数にして、フレームワークに渡せるようにすればいいわけです。
下記のようなイメージになります。
typedef struct _tagDBLoadApp {
...
CALLBACK1 UploadFunc;
...
} TDBLOADAPP;
typedef struct _tagTable {
....
データベース情報関係
} TTABLE;
/* 実際のテーブルへのローディングロジックを実装
テーブル毎に異なる部分は、情報は、TTABLE 構造体から取得
また、処理ロジック上異なるものは、アプリケーションに設定
されたコールバック関数を呼び出すことにより対応。
ロジックの大部分は、再利用可能である。
*/
int DBLoadApp_Run(TDBLOADAPP* pApp, FILE* fp, TTABLE* pTbl)
{
DBHANDLE hDB;
FILE* fp;
hDB = Table_Connect(pTbl);
fp = fopen(
.....
/* テーブルへのアップロード */
while (fgets(szBuf, sizeof(szBuf), fp) != NULL) {
(*(pApp->UploadFunc))(hDB, szBuf);
.....
} /* end of while */
}
int main()
{
....
pApp = DBLoadApp_Alloc();
pTable = Table_Alloc(・・・);
fp = fopen(FileName, "r);
....
/* 処理が違う部分のコールバック関数を設定 */
DBLoadApp_SetUploadFunc(pApp, TableA_Upload);
....
/* データロードの実行 */
DBLoadApp_Run(pApp, fp, pTable);
....
fclose(fp);
Table_Free(pTable);
DBLOadApp_Free(pApp);
}
プログラムの殆どは、アップロード用アプリケーションとして一度書いたら再利用可能です。
テーブル毎に記述が必要なのは、上の例だと、TableA_Upload という関数のみです。
つまり、テーブル分だけ、行を編集するための関数をつくって、main関数の中でセットするだけです。
実際のフレームワーク部分、DBLoadAppのAlloc、Run、Free等は、一度作成してしまえば、手をいれなくても動作します。
int TableA_Upload(DBHANDLE hDb, char* szBuf)
{
char szItem1[ITEM1_LEN+1];
.....
strncpy(szItem1, szBuf, ITEM1_LEN);
.....
ExecSql("update ... item1 .....");
....
}
よくよく考えて見ると、アプリケーションは類似機能が多いものです。
大抵は、ひとつ作ってコピーして一部変更すれば動作してしまったりします。
どこが違って何が同じか、その違いを分離できれば、開発生産性は格段に上がります。
前回と今回で、C言語の共通化とフレームワーク化について書いてみました。
ただ実際には、やはりオブジェクト指向に対応している言語の方が簡単に共通化やフレームワーク化が可能です。
C言語について、16回にわたり書いてきましたが、フレームワークまで書いたので、今回で一区切りとさせていただきます。
最近は、プログラムは、Pythonを使うようになりました。
C言語はC言語で性能面や軽さから組込み系に対応できるなどのメリットはありますが、日常利用する業務効率化やWeb操作のプログラムなら、Pythonの方が生産性があがります。
次回からは、プロジェクトや問題解決関連と、プログラミングであればPythonまで手を広げようと考えています。