ここまで作ったルーティング・レジストリ・名前からのハンドラー生成を1つの Dispatcher クラスにまとめ、掲示板に組み込む。URL を渡せばハンドラーが選ばれて動き、機能を足すときは add_route を1行足すだけ。第1回の if/elsif と並べて比べます。
/posts、/posts/new、/posts/123 のように、Web アプリケーションでは URL の形でハンドラーを選びたい。パターンとハンドラーを add_route で登録し、match で正規表現を順に試して、パスに合うハンドラーを返す Router クラスを作ります。
レジストリではハンドラーを使う前に全部登録しておく必要があり、10個、20個と増えると登録のコードも伸びる。'list' から Handler::List のようにクラス名を組み立て、Module::Load の load で読み込んで new する。登録しなくても名前だけでハンドラーが使えます。
ハンドラーが増えると、どれをいつ set_handler で差し替えるかを呼び出し側が覚えておくことになる。名前とハンドラーの対応をハッシュの属性に持たせ、register_handler で登録しておき、dispatch('list') のように名前だけで呼び分けます。
handler 属性が is => 'ro' だと、一覧を表示していた Dispatcher をフォームの表示に切り替えられない。属性を is => 'rw' にし、意図が読み取れる set_handler メソッドを用意して、1つの Dispatcher のままハンドラーを差し替えます。
利用側で ListHandler->new して run を呼んでいると、どのハンドラーを使うかの判断が呼び出し側に散らばり、ハンドラーを足すたびに呼び出し側も直すことになる。ハンドラーを属性に持つ Dispatcher クラスを作り、Moo の handles で run を委譲します。
ハンドラーは run を持つ約束なのに、新しく足したクラスで execute と書いても、呼び出すまでエラーにならない。Moo::Role の requires 'run' で Handler ロールを作り、with で適用したクラスが run を持たなければ起動時に止めます。
実際の機能はデータベースへのアクセス、バリデーション、テンプレートの描画と大きくなり、無名サブルーチンには収まらない。ListHandler や FormHandler のように機能ごとに Moo のクラスを作り、どれも同じ run メソッドで呼べるようにします。
ハッシュにメソッド名の文字列を入れると、処理の本体は別の場所に書くことになる。sub { ... } の無名サブルーチンを変数やハッシュに入れ、->() で呼び出す。アクション名と処理の対応が1か所で見渡せるようになります。
if/elsif で action を順番に比べる代わりに、アクション名とメソッド名の対応をハッシュに書き、$self->$method() で呼び出す。機能を足すときはハッシュに1行とメソッドを足すだけで、dispatch には手を入れずに済みます。
前シリーズで作った掲示板に、一覧・フォーム・スレッド・検索・通知と機能を足すたびに、action を調べる if/elsif が1本ずつ伸びる。機能追加のたびに同じメソッドを直すことになる問題を、Perl と Moo のコードで確かめます。
変数とサブルーチンだけで書いた Perl は、データと処理が散らばり、どこで値が変わったのか追えなくなる。Moo で掲示板アプリを1つ育てながら、クラス・カプセル化・継承・ロール・委譲・型制約まで、オブジェクト指向の基本を1回に1つずつ身につける全12回の案内板です。
GitHub Copilot の300プレミアムリクエストを使い切ろうと挑戦した結果、100%達成できませんでした。短期集中利用で見えてきたレート制限の実態、Claude Opus 4.5 の優れた推論能力、そしてAIエージェントの自律的判断について考察します。
like_count に文字列を入れても代入は通り、足し算をした所でおかしな結果になって初めて気づく。Moo の isa に Types::Standard の Int などを指定し、値を入れた瞬間にエラーにします。全12回で作った掲示板のクラス構成と、学んだ概念の一覧も付けた完結回。
メッセージの追加・取得・件数のメソッドが増えるたびに Board が太り、掲示板としての処理が埋もれる。一覧の管理を MessageList クラスに切り出し、Moo の handles で Board からそのメソッドを直接呼べるようにします。