「コード考古学者ハリスの冒険」は、レガシーコードの遺跡を考古学者ハリスと相棒のギズモが調べ、GoF のデザインパターンで直していく全24話の連載です。GoF の23種に、Null Object を加えた24本です。各話では、遺跡のコードが抱えた困りごとを見立て、パターンで直すまでを冒険物語としてたどります。
どの話からでも読めます。実装は Perl と Moo ですが、コードを書き慣れている必要はありません。直す前と後のコードを見比べて、何が変わったかを追えれば十分です。
このページは目次を兼ねた案内板です。初めてなら「まず読むなら」の3本から、手元に困っているコードがあるなら「困りごとから探す」から、パターン名で引きたいなら「GoF の分類で探す」から選んでください。
まず読むなら
- Factory Method — 環境が増えるたびに膨らむ if/elsif を、道具の選択と生成を分けて片付ける回。多くの現場で最初に出会う困りごとで、ほかのパターンを読む足場になる
- Null Object — undef チェックを1か所書き忘れて落ちる回。Perl を書いているなら一度は踏む罠で、明日のコードにそのまま使える
- Facade — 決まった順に呼ばないと壊れる部品群を、窓口1つにまとめる回。途中で失敗したときの巻き戻しまで扱うので、手順書をコードに置き換える実例になる
困りごとから探す
条件分岐が伸び続けて、足すたびに本体を書き換えている
- Factory Method — 環境ごとに道具を作り分ける if/elsif
- Strategy — 罠ごとに防御を書き分ける defend メソッド
- State — 状態を確かめる if-else が並んだタレットの制御
- Chain of Responsibility — 権限チェックを全部抱え込んだゲート
- Composite — 部品か集合体かを ref と isa で見分ける再帰処理
- Visitor — 型ごとに処理を書き分ける呼び出し側
- Interpreter — 正規表現の場当たりな解析に条件を足せない
コピペや、組み合わせごとのクラスが増えていく
- Template Method — 同じ流れの解除コードを10個コピペしている
- Decorator — 継承では暗視と熱感知の組み合わせごとにクラスが要る
- Bridge — 継承とロールを合わせたら同名メソッドが衝突した
同じはずのオブジェクトが食い違う、不完全なまま使われる
- Singleton — 同じクラスなのに別のインスタンスを見ていて、認証が通らない
- Abstract Factory — 砂漠用の防護服に氷雪用の動力炉が組み合わさる
- Builder — 引数が散らばって未完成のオブジェクトが出回る
- Prototype — 複製したのに、片方の変更がもう片方を壊す
- Null Object — undef の判定漏れで処理が止まる
部品同士が直接呼び合っていて、1つ足すと全体が揺れる
重い、遠い、データの形がばらばら
- Flyweight — 数千体のゴーレムが同じ設定を抱えてメモリが尽きる
- Proxy — 遠くて重いデータ源へのアクセス制御とキャッシュ
- Iterator — 配列と連結リストが混在していて、走査が構造に縛られる
古い仕組みに合わせたい、手順を間違えると壊れる
操作や状態を元に戻したい
GoF の分類で探す
生成に関するパターン (Creational Patterns)
- 認証済みのはずなのにゲートが開かない。クラスが同じでも別のインスタンスを見ていた【Singleton】
- 環境が増えるたびに膨らむ if/elsif。道具の選択と生成を分けて直す【Factory Method】
- 砂漠用の防護服に氷雪用の動力炉が組み合わさる。一式をまとめて作って防ぐ【Abstract Factory】
- 引数が散らばって未完成のオブジェクトが出回る。組み立てを専用の部品に任せる【Builder】
- 複製したはずのオブジェクトが、片方を変えるともう片方も壊れる。浅いコピーを避けて複製する【Prototype】
構造に関するパターン (Structural Patterns)
- メソッド名もデータの形も違う古い端末を、今のスキャナーから読みたい。変換役を挟む【Adapter】
- 継承とロールを合わせたら同名メソッドが衝突し、初期化順序が崩れて暴走した。操作と対象を分けて組む【Bridge】
- 部品か集合体かを型で見分けて、再帰で電源を入れる。同じ扱いにそろえる【Composite】
- 暗視も熱感知も付けたいのに、継承では組み合わせごとにクラスが要る。重ね着で機能を足す【Decorator】
- バルブ、ダクト、点火を決まった順に呼ばないと爆発する。起動手順を窓口1つにまとめる【Facade】
- 数千体のゴーレムが同じデータを抱えてメモリが尽きる。共通部分を1つにまとめて共有する【Flyweight】
- 遠くて危険なデータ源へ、アクセス制限と取得の手間を呼び出し側に背負わせたくない。代理役を立てる【Proxy】
振る舞いに関するパターン (Behavioral Patterns)
- 権限チェックを全部抱え込んだゲートが、条件を足すたびに膨らむ。審査を順に回す仕組みにする【Chain of Responsibility】
- レバーが機器を直接呼ぶ作りで、操作の履歴も取り消しもできない。操作をオブジェクトにする【Command】
- 正規表現で場当たりに解析していたスクリプトに、条件を足すたび限界が来る。文法を構文木にする【Interpreter】
- 配列がむき出しで、構造が変わるたびに呼び出し側の走査を書き直すことになる。走査を専用の部品に任せる【Iterator】
- モジュール同士が直接呼び合って、依存が網の目になる。やり取りを仲介役に集める【Mediator】
- カプセル化を壊さずに、状態を退避して後で戻したい。中身を覗かせない保管箱を作る【Memento】
- 崩落の検知に、ブザーと扉と照明を直接呼んでいる。変化を知らせるだけにして連動させる【Observer】
- 状態を確かめる if-else が、メソッドごとに泥沼になる。状態ごとの部品に振る舞いを持たせる【State】
- 罠が増えるたびに defend メソッドを開いて書き換える。防御の方法を部品にして差し替える【Strategy】
- 解除コードを10個コピペして、手順の修正が全部に及ぶ。共通の流れを親にまとめる【Template Method】
- 新しい操作を足すたびに、型判定の分岐が呼び出し側に増える。操作を訪問者にして追加する【Visitor】
- undef チェックを1か所書き忘れて落ちる。「何もしない」オブジェクトで分岐ごと消す【Null Object】
Null Object は GoF の23種には含まれません。この連載では、undef の扱いを整理する補助の1本として、振る舞いのパターンに並べています。
