開発プロセス●●●○○

デザインパターン

デザインパターン

繰り返し現れる設計課題への定石解に名前を付けたカタログ。設計の共通語彙になる。

概要

デザインパターンは、ソフトウェア設計で繰り返し現れる課題に対する「定石の解き方」に名前を付けて整理したカタログです。「オブジェクトの生成を1か所に集約したい」「状態の変化を複数の画面に通知したい」といった課題は、アプリの種類が違っても構造としては同じ形で何度も現れます。先人が磨いてきた解法を「Singleton」「Observer」のような名前で呼べるようにしたものがデザインパターンです。

最大の価値は、コードの再利用ではなく語彙の共有にあります。「ここは Strategy パターンで差し替え可能にしよう」の一言で、クラス構成・意図・トレードオフまで含めた設計方針がチームに伝わる。設計レビューやコードリーディングの場面で、パターン名は圧縮率の高い共通言語として機能します。フレームワークやライブラリのドキュメントにも Factory、Adapter、Proxy といった名前は頻出するため、読み解きの前提知識にもなっています。

なぜ生まれたか

発想の源流はソフトウェアではなく建築にあります。建築家クリストファー・アレグザンダーは1970年代、「良い建物や街には繰り返し現れる構造がある」として、それらを名前付きの解法集にまとめる「パターンランゲージ」を提唱しました。個々の名人芸に閉じていた設計知識を、名前・課題・解法・帰結のセットとして記述すれば、他者が学び組み合わせられる — この考え方をソフトウェアに持ち込んだのが、1994年の『Design Patterns』(通称 GoF 本。著者4人が Gang of Four と呼ばれたことに由来)です。

当時のオブジェクト指向開発では、経験者は「継承より委譲」「実装ではなくインターフェースに依存する」といった勘所を体で知っていましたが、それを新人に伝える体系的な言葉がありませんでした。GoF は23個のパターンとしてこの暗黙知を明文化し、結合度と凝集度を改善する具体的な手筋を、誰でも参照できる形にしたのです。

詳細

3つの分類と代表パターン

GoF の23パターンは、扱う課題の種類で3つに分類されます。生成に関するパターンは「オブジェクトをどう作るか」を扱います。インスタンスを1つに限定する Singleton、生成手順をサブクラスに委ねる Factory Method、複雑な組み立てを段階的に行う Builder などです。構造に関するパターンは「クラスやオブジェクトをどう組み合わせるか」を扱います。互換性のないインターフェースを変換して繋ぐ Adapter、本物の代理を立てて呼び出しを仲介する Proxy、木構造を単一・複合の区別なく扱う Composite などです。振る舞いに関するパターンは「オブジェクト間の協調と責任分担」を扱います。状態変化を購読者たちへ通知する Observer、アルゴリズムを差し替え可能な部品に切り出す Strategy、処理の骨格だけ親が決めて詳細を子に委ねる Template Method などが代表です。

GoF デザインパターン 23種課題の種類で3つに分類される生成どう作るかSingletonFactory MethodBuilder生成の知識を1か所に閉じ込める構造どう組み合わせるかAdapterProxyComposite部品どうしの継ぎ目を柔らかくする振る舞いどう協調するかObserverStrategyTemplate Method責任の分担と通知の流れを整理する
GoFデザインパターンの3分類と代表例

パターンが目指すもの

23個の根底に流れる原則は「変わるものと変わらないものを分離し、変わる部分を差し替え可能にする」ことです。Strategy はアルゴリズムを、Observer は通知先を、Factory は生成対象を、それぞれ本体から切り離します。これはSOLID原則、とりわけ開放閉鎖原則(拡張に開き修正に閉じる)や依存性逆転原則の具体的な実現手段であり、依存性注入もこの系譜に連なる技法です。つまりパターンは暗記対象のカタログではなく、「疎結合・高凝集を実の設計でどう達成するか」の実例集として読むのが本来の使い方です。

パターンは今も現役の技術基盤に息づいています。ORM の内部には Unit of Work や Identity Map といったパターンが、GUI やフロントエンドの状態管理には Observer の系譜が、MVC のようなアーキテクチャパターンにも複数の GoF パターンが組み込まれています。名前を知っていると、これらのライブラリの設計意図が透けて見えるようになります。

落とし穴 — パターン病

デザインパターンを覚えたての時期に陥りがちなのが、パターンを使うこと自体が目的化する「パターン病」です。if 文2つで済む処理に Strategy と Factory を導入し、クラスが5個に増えて読みにくくなる — 課題がまだ存在しないのに解法だけ先に適用してしまう倒錯です。パターンには必ず「どんな課題のときに使い、どんな代償があるか」が定義されており、課題側が現れていないなら適用しないのが正解です。実務では、まず素直に書き、変更の圧力が実際にかかった箇所をリファクタリングでパターンの形へ育てていく進め方が健全です。

もう一つ知っておきたいのは、パターンの必要性が言語の進化とともに変わることです。GoF は C++ と Smalltalk を前提に書かれており、たとえば Strategy は関数を第一級の値として渡せる言語なら単なる高階関数で済みます。Iterator は多くの言語で構文(for-of や foreach)に吸収され、Singleton はモジュールシステムがあれば専用クラスは不要です。「パターンとは言語の表現力の穴を人力で埋めるレシピである」という見方もあり、どの言語で何が構文に昇格済みかを意識すると、パターンを盲目的に移植する失敗を避けられます。それでも、課題と解法に共通の名前を付けて設計を語るという営みそのものは、言語がどれだけ進化しても価値を失いません。