Entry

プログラミングメモ - C++ で Web コンテナの妄想ふたたび

2009年03月13日

定期的に作りたい衝動がこみ上げるので,またちと考える。いつも考えていて詰まってるところ。

Web コンテナ/フレームワークというと,FrontController パターンを使って,アクセスポイントを1点に絞るのが普通です。もちろん,ユーザ/クライアントは,やりたいことに応じて異なる URL にアクセスするんだけれども,内部では mod_rewrite なんかを使って,ひとつのプログラムにリクエストの受付を集中させています。こうすると,機能ごとにリクエストの受付ルーチンを持たなくていいので,保守性が向上するんです。

ただ,ここで問題となるのが,HTTP リクエストからどうやって目的の機能(クラス)を作るかです。COM や CORBA と違って,Web ベースのアプリケーションは HTTP リクエストでデータをやりとりするわけで,これが問題になる。つまり,HTTP リクエストは文字列のやりとりなので,文字列をクラスの呼び出しに変換する必要があるわけです。

この点,J2EE ベースの Struts なんかは,ActionMapper クラスで,HTTP リクエストを目的の機能を持ったクラス(Action)にマップしています。ただこれ,Java だからできるリフレクションを使ってるんですよね……。C++ でも,頑張ればリフレクションもどきを作れるんですけれど,処理系に依存するちと危ない処理になってしまいます。んなもんで,別の方法を考える必要がある。

今のところ考えた方法は,こんな感じで地道に switch-文で分岐する方法です。GoF に言う Strategy パターンの一種を使ってみる。

class LoginContext : public Context {};
class EditContext  : public Context {};
class DelteContext : public Context {};

auto_ptr<Context>
ContextMapper::getContext(Request& request, Response& response) throw (Exception) {
    Context* context = 0;
    // ID から作る Context を決める
    switch (request.getContextId()) {
    case ContextFactory::LOGIN;
        context = ContextFactory::create<LoginContext>(request, resonse);
        break;
    case ContextFactory::EDIT;
        context = ContextFactory::create<EditContext>(request, resonse);
        break;
    case ContextFactory::DELETE
        context = ContextFactory::create<DeleteContext>(request, resonse);
        break;
    default:
        throw Exception("invalid context id.");
    }
    if (context == 0) {
        throw Exception("create context failed.");
    }
    auto_ptr<Context> ret(context);

    return ret;
}

request.getContextId() で得られる ContextId は,機能(Context)に応じた一意の数値です。これは,単純な連番ではあまり意味がなくて,リクエストにある何らかの情報から計算で求められる必要があります。いや,求められなくてもいいんですけどね。かっこ悪い switch-文がひとつ増えてしまう。これは多分,SCRIPT_FILENAME あたりから,よさげなハッシュ関数を使って作れるんじゃないかと思います。数値の定義部は前もって計算しておいて,enum に収めておく(もちろん,補助プログラム/スクリプトを使ってソースを生成する)。

これなら割といけるんでねいだろうか。

もっとも,この方法は switch-文が増えるのが最大の欠点です。switch-文が増えると何が困るのかというと,単純に保守性が低下するんです。仕事の話になっちゃうけれども,以前あたしがやってた,製造系のプロジェクトでは,画面が500以上あったりしました。1画面1機能として,500も case-文を書くのかっつーと,ちときつい。こゆのは XML かなんかでメタファイルにまとめておいて,コンパイル時にソースを生成する方がいいのかしらん。そもそも,個人が使うウェブアプリなんて,画面もせいぜい20~30前後なんでしょうけどね。

一方,この方法は割と原始的なものの,Java のリフレクションよりもコストはかからないんじゃないだろうか。あらかじめコンパイルしておくからって単純な根拠なんですけど。

最近のウェブアプリには,DB の中身を右から左に流すようなもんだけでなく,大規模演算をさりげなく行うものも増えてきました。おそらく,その手のサイトのバックエンドは C/C++ のような,高速な言語で開発しているはず。こゆコンテナがあると便利なんですけどね。だからといって,全部 C++ で作る必要もないわけですけど。

Trackback
Trackback URL:
Ads
About
Search This Site
Ads
Categories
Recent Entries
Log Archive
Syndicate This Site
Info.
クリエイティブ・コモンズ・ライセンス
Movable Type 3.36
Valid XHTML 1.1!
Valid CSS!
ブログタイムズ

© 2003-2012 AIAN