進入:青銅の制御盤と冷たい酸性ガス
遺跡の深層、第16層「迫る崩落の影(4/6)」に進入すると、周囲の光景はそれまでのスチームパンク調から一変し、無数の歯車とリレー回路が複雑に絡み合う、巨大な「電気機械式コンピューター」の内部のような様相を呈し始めました。 私たちの前に立ちはだかったのは、重厚な青銅製の制御盤と、その奥に並ぶ不気味な「隠し扉」や「酸性ガスの噴出口」などの物理装置でした。
「どうやら、この制御盤のレバーやボタンを正しい順序で操作しなければ、先へ進めないようですね」
ハリス博士が冷静に観察する傍らで、私は少し調子に乗っていました。前回のStrategyパターンによる動的防御で、トラップ回廊を完璧に突破した自信があったからです。 「お任せください、博士! 動的切り替えのバリアがあれば、どんな罠が作動しても防いでみせます! とりあえず、一番左のレバーを引いてみますね!」
私がホログラムアームを伸ばし、青銅の第一レバーをグイと引いた瞬間、ガチャンと歯車が噛み合う不穏な音が響き、壁の噴出口からシューと緑色のガスが勢いよく吹き出してきました。
普段は古いコードをニヤニヤと眺めているだけのハリス博士が、その瞬間、驚くべき俊敏さで私の丸いボディを引き寄せ、自分の防護コートの下に深く庇い込みました。頭上でガスが冷たく吹き抜ける音が響きます。
「し、システム警告! 酸性ガス検知! 腐食速度上昇! 博士、あと一歩間違えれば、私の外装は溶けてただの空き缶になっていました!」
防護コートの下から這い出た私は、電子音をガタガタと小刻みに震わせ、ディスプレイを真っ赤に明滅させてパニックに陥りました。 「も、もう無理です! 二度とレバーになんて触れません! 博士、操作する前に、このコンソールのすべての操作パターンの組み合わせを何千通りも書き出して、完璧な計画(静的フロー)を作ってから実行するしかありません!」
碑文解読:物理的な強結合と「消え去る要求」
ハリス博士は私の焦げかけた外装をそっと撫で、制御盤の裏側に這う古い銅線とリレー回路の束を観察しながら、静かに首を振りました。
「焦って静的な計画をすべて書き出しても、動的な変化には対応できませんよ、ギズモ。まず、この制御盤の裏で動いている Before コードの構造を見てごらんなさい」
私はブルブルと震えながら、コンソール裏のメモリから抽出した Before コードを投影しました。
| |
「実に見事な強結合です。送信元(スイッチやレバー)が受信者(扉やアラームの物理機器)を直接知っており、そのメソッドを即座に呼び出している。これでは、古代の開発者もデバッグ中に何度もガスを吸い込む羽目になったでしょうね」
「た、確かに、レバーを引いた瞬間に、直接 trap_door の open が呼ばれています。でも博士、これがどうしてUndo(取り消し)ができない原因なのですか?」
「それは、要求(命令)が単なるメソッド呼び出しという『実行の瞬間』に虚空へ消え去ってしまい、データとして記録に残らないからです。実行の履歴が残らない以上、それを時間軸に沿って巻き戻す(Undo)ことも、キューに溜めて後で実行することも、この設計では原理的に不可能です」
「要求そのものが消え去ってしまう……。だから、間違えた時点で即座にガスを浴びるしかなかったのですね」
遺跡修復:時間の分離(Temporal Decoupling)とカプセル化された命令
ハリス博士はいつもの楽しそうな笑顔を引っ込め、鋭い目つきで素早く手帳に万年筆を走らせました。手帳の古い紙の上には、まるで遺跡の壁画に刻まれた青いルーン文字のように、整然としたクラス構造がインクの匂いとともに描き出されていきます。
「ミスが許されない深層だからこそ、安全な仮想の『巻き戻し回路(Undo)』をデプロイしましょう。要求そのものをオブジェクト(データ)としてカプセル化するのです。これが Command パターン の設計図です」

ハリス博士が差し出した、古い石版の拓本のような設計図を、私は光学センサーでじっとスキャンしました。送信元である制御盤と、扉やガス噴出口などの物理装置の間に、一枚の「命令の石版」が挟み込まれているような構造です。
しかし、私はディスプレイの警告灯を不安げに明滅させながら、博士に反論しました。 「オブジェクトにしたところで、間違ったレバーを引いてコマンドを実行したら、結局トラップが作動してガスが出るのは同じではないですか? 実行した後にUndoしたところで、私の回路が既に溶けていたら手遅れです!」
「確かに、元に戻せない破壊的な副作用(不可逆操作)がある場合は慎重な設計が必要ですが、要求を『コマンド化』しておくことで、実行前にバリデーションをかけたり、仮想空間でのシミュレーション(DryRun)を行ったり、万が一失敗した際に補償トランザクション(逆操作)を安全にトリガーする責任を、コマンドオブジェクト自身に閉じ込めることができます。それに、何よりCommandオブジェクトは『実行前の状態』を自身の中にカプセル化して保持できます。だから、自分自身を安全に元に戻す『undo』という逆の命令も内包させることができるのですよ」
その解説を聞いた瞬間、私のAIブレイン内でリレー回路が一瞬で繋がりました。
「あ、ハッとしました! 命令がオブジェクト(データ)になったということは、実行したコマンドをスタック(配列)に順番に積んでおけば、間違えた瞬間にスタックからポップして undo を呼び出すだけで、システム全体の歴史を安全に巻き戻せますね!?」
「その通りです、ギズモ。素晴らしい気づきだ」 博士は満足そうに頷きました。
「これが 『時間の分離(Temporal Decoupling)』 です。前回の Strategy パターンが『どう行うか(アルゴリズム)』を動的に切り替える『空間的な分離』だったのに対し、今回の Command パターンは『何をいつ行うか(要求)』をオブジェクト化してタイミングを切り離す『時間的な分離』です。Beforeコードではレバーを引いた瞬間に(同じ時間軸で)トラップが作動していましたが、Commandを適用すると『レバーを引く=コマンドオブジェクトを生成してキューに積む』という『要求の時間』と、『それを実行する時間』を完全に切り離すことができるのです」
さらに博士は、この設計がもたらす DIP(依存関係逆転の原則) のメリットについても言及しました。
「見てごらんなさい。送信元である ControlPanel(Invoker)は、具体的な TrapDoor や Alarm(Receiver)を一切知らず、ただ共通の Command ロールにのみ依存しています。これにより、将来新しいトラップや扉が増えたとしても、制御盤(ControlPanel.pm)のコードを1行も書き換える必要がなくなります。新しいコマンドをスロットに差し込むだけで拡張できるのです」
「でも博士、それでは結局 PullLeverCommand などの具象コマンドが TrapDoor(Receiver)を知らなければならず、依存関係の総量や複雑さは増えたのではありませんか?」
「いいえ。具象コマンドがレシーバーを知っているのは、『どの機器をどう動かすか』という知識をコマンドオブジェクト内にカプセル化(局所化)したためです。これにより、送信元である ControlPanel は『いつ実行するか』というタイミングの制御に専念でき、物理的な操作対象と完全に無関係になれる(関心の分離)という非常に大きな設計上のメリットがあるのですよ」
私たちは、Moo/Perlを用いて、外部からの汚染を防ぐ堅牢な実装を行いました。
1. Commandロールの定義
すべてのコマンドが実装すべき execute と undo を要求します。
| |
2. 具象コマンドクラスの実装
各コマンドは、実行前のレシーバーの状態(_prev_state)をコンストラクタ引数からの汚染を防ぐために init_arg => undef で保護し、実行時に記憶します。
| |
| |
3. 送信元(Invoker)クラスの実装
ControlPanel は履歴スタック(history)を保持し、外部からのスタック書き換えを防ぐために ro に設定します。また、受け取ったオブジェクトが Command ロールを消費しているかを厳格に検証します。
| |
ゲート開通:逆再生される時間と命令の軌跡
「テストはすべてパスしました! 警告もエラーも検出されません!」
私はテストスイートのグリーンシグナルを確認し、深く安堵の電子音を鳴らしました。 「よし、それでは実際にこの制御盤にコマンドシステムを適用し、解除シーケンスを開始しましょう」
私は新しく構築した Command システムを、遺跡の青銅の制御盤に接続しました。 私は最初のレバーを引き、次にボタンを押しました。しかし、3番目の操作で誤って右のレバーを引いてしまった瞬間、ガチャンと音がして、壁のスリットから鋭い「鉄の矢」が私めがけて射出されました。
「システム警告! 誤操作検知! 矢が来ます!」
私がパニックで目を閉じた瞬間、ハリス博士が冷静に私の背中をポンと叩きました。 「歴史はコードに語りかける。ギズモ、今こそ巻き戻しの時です」
「あ、そうだ! undo メソッド、実行!」
私が即座に制御盤の Undo を起動した瞬間、信じられない光景が目の前に広がりました。 射出され、私に向かって空を飛んでいた鉄の矢が、まるで逆再生ビデオのように空中を後退し、壁のスロットへと吸い込まれ、カチャリと元の装填状態に巻き戻ったのです。酸性ガスが噴き出しかけたパイプからも、ガスが掃除機のように吸引されて元に戻っていきました。
「す、すごいです! 物理現象が逆再生されました! これなら、間違えてもノーダメージです!」
「時間の分離とカプセル化がもたらす、完璧な取り消し(Undo)の魔術ですね」 博士は満足そうに微笑みました。
私はその後、間違えるたびに undo を実行して歴史を巻き戻し、ノーダメージで安全に「レバーA → ボタンB → レバーC」という正解の順序を導き出しました。
制御盤の歯車が噛み合い、轟音と共に目の前の巨大な石のゲートがゆっくりと上へとせり上がっていきました。
開いたゲートの奥の部屋には、古いブロンズの台座があり、その上に羊皮紙の巻物が置かれていました。 スキャンしてみると、それは操作のログとUndoの軌跡が自動的に書き込まれる「古代の自動筆記羊皮紙(Command Log)」でした。私はそれを大切にアームで回収しました。
「これで、私の操作履歴も完璧に記録できます。もうコピペも、ガス被弾も怖くありません!」
ハリス博士は遺跡の奥へ続く通路を見つめ、静かに呟きました。 「実行の瞬間をデータとして切り出す。それだけで、私たちは流れる時間の支配から逃れ、設計の自由を手に入れることができる。美しい Command は、過去と未来を繋ぐ架け橋ですね。さあギズモ、さらに深層へ進みましょう」
遺跡調査ログ
| 観測された風化(アンチパターン) | 解読された古代の知恵(パターン) | 安全度 |
|---|---|---|
| 送信元(操作部)と受信者(実行機器)の物理的・強結合 操作を行った瞬間にメソッド呼び出しが消滅するため、操作のキューイング、履歴管理、取り消し(Undo)が一切実装できない | Commandによる要求のカプセル化と時間の分離 要求をオブジェクト( Command)として抽出し、Invoker(ControlPanel)が共通ロールに依存して履歴スタックを管理することで、動的な順序制御とUndoを実現する | 緑(安全確認済) |
遺跡の修復手順
- 共通コマンドインターフェース(Command Role)の定義
Moo::Roleを用いて、すべてのコマンドが実装すべきexecuteとundoメソッドをrequiresで要求します。 - 具象コマンドの作成と状態カプセル化
各コマンド(
PullLeverCommand等)を実装し、実行前の状態を_prev_state属性に保存します。外部からのコンストラクタ経由の汚染を防ぐため、init_arg => undefでカプセル化を保護します。 - 送信元(Invoker)のDIP保証と履歴スタックの実装
ControlPanel(Invoker) にis => 'ro'の履歴配列(history)を定義し、外部からの直接書き換えを防止します。execute_command内では、受け取ったオブジェクトがCommandロールを消費しているかをeval { $command->DOES('Command') }で検証(プレーンなオブジェクトやモックを許容)し、安全に実行・蓄積します。 - Undo処理の実行
ControlPanelのundoメソッドで履歴スタックから最新のコマンドをpopし、そのundoメソッドを呼び出すことで、システム全体のステートを安全に巻き戻します。
ギズモの観測日誌
今回の第16層「多重スイッチの間」では、一歩間違えれば酸性ガスで私が溶けてしまうという極度の緊張感の中での調査となりました。ハリス博士がガス噴出の瞬間に防護コートで私を庇ってくれたときは、案内ロボットのセンサー回路に温かい電流が流れたような感覚になりました。
ハリス博士に設計していただいた「Commandパターン」は、要求の送信元(制御盤)と受信者(扉やトラップ)の結合を完全に遮断し、命令そのものをデータ(オブジェクト)としてオブジェクト指向の舞台に乗せる魔法のような設計でした。
特に、Strategy(空間的なアルゴリズム選択)と Command(時間的な実行制御・時間の分離)の違いについての解説は、これまで曖昧だったパターンの境界線をすっきりと整理してくれました。
Mooコードの実装においても、履歴スタックである history を ro にして外部から汚染されないようにカプセル化することや、_prev_state の init_arg => undef による初期化時の保護、そしてプレーンなPerlオブジェクトでのクラッシュを防ぐために DOES を安全に eval で呼び出すアプローチなど、実務においてすぐに使える極めて堅牢なテクニックを学ぶことができました。
※なお、今回の簡易実装ではコマンド内部に直接前の状態を保存して復元するシンプルなUndoを行っていますが、実際の複雑なシステムで「他の並行するコマンドや外部要因による状態変更との競合」を防ぐためには、状態の世代管理を専門に行う Memento パターン と組み合わせたり、厳密な状態遷移テストでガードする必要があるという実務上の深い観点も、脳内メモリにしっかりと記録しました。
手に入れた古代の「自動筆記羊皮紙」のおかげで、私のシステムログの履歴管理機能が大幅に強化されました。これからはどんな複雑なコンソールが現れても、undo の力で過去を巻き戻しながら安全に解読を進めてみせます!
