はじめに
ソフトウェア開発において「デザインパターン(Design Patterns)」は、よくある設計上の課題を解決するための 再利用可能な設計知識 です。
単なるコードテンプレートではなく「設計の知恵袋」であり、チーム内で共通言語として使える強力なツールです。
この記事では 23種類のGoFデザインパターン を体系的に整理して紹介します。
1. デザインパターンとは?
デザインパターンとは、ソフトウェア開発において繰り返し現れる課題に対してまとめられた、再利用可能な設計上の解決策です。
具体的なコードそのものではなく、経験の集大成+設計の考え方 です。
目的
-
コードの再利用性向上:同じような問題にすぐ適用できる
-
保守性向上:構造が整理され、変更や拡張が容易
-
共通言語化:開発者同士で「シングルトン」「オブザーバ」などと呼ぶだけで設計意図が伝わる
💡 たとえ
プログラムを家づくりに例えると、デザインパターンは「建築図面のひな型」。
適切に使えば堅牢で美しい建物ができるが、乱用すれば逆効果になる。
2. デザインパターンの三大分類
GoF(Gang of Four)の著書 「Design Patterns: Elements of Reusable Object-Oriented Software」 によると、デザインパターンは 3つのカテゴリ、23種類 に整理されています。
2.1 生成に関するパターン(Creational Patterns)
オブジェクトの生成方法を工夫し、システムと生成処理を疎結合にする。
-
シングルトン(Singleton)
あるクラスのインスタンスを一つだけに制限(例:設定管理、スレッドプール)。 -
ファクトリーメソッド(Factory Method)
オブジェクト生成のインターフェースを定義し、サブクラスに委譲。 -
抽象ファクトリ(Abstract Factory)
関連する一連のオブジェクトをまとめて生成(例:クロスプラットフォームのUI部品)。 -
ビルダー(Builder)
複雑なオブジェクトを段階的に組み立てる(例:PCの組立)。 -
プロトタイプ(Prototype)
既存のオブジェクトをコピーして新しいインスタンスを作る。
2.2 構造に関するパターン(Structural Patterns)
クラスやオブジェクトを柔軟に組み合わせて大規模構造を扱いやすくする。
-
アダプタ(Adapter)
既存のインターフェースを別の形に変換(例:電源変換プラグ)。 -
ブリッジ(Bridge)
抽象と実装を分離し、それぞれ独立に拡張可能にする。 -
コンポジット(Composite)
ツリー構造で「全体と部分」を統一的に扱う(例:フォルダとファイル)。 -
デコレータ(Decorator)
オブジェクトに動的に新しい機能を追加(例:コーヒーにミルクを追加)。 -
ファサード(Facade)
複雑なサブシステムを簡単に利用できるように統一窓口を提供。 -
フライウェイト(Flyweight)
多数の小さなオブジェクトを共有してメモリ節約(例:文字オブジェクトプール)。 -
プロキシ(Proxy)
アクセス制御や遅延ロードのための代理を提供。
2.3 振る舞いに関するパターン(Behavioral Patterns)
オブジェクト間の連携や責任分担を整理する。
-
オブザーバ(Observer)
一対多の依存関係。状態が変わると関連オブジェクトに自動通知(例:イベントリスナー)。 -
ストラテジー(Strategy)
複数のアルゴリズムを切り替え可能に(例:支払い方式の選択)。 -
コマンド(Command)
リクエストをオブジェクトとしてカプセル化(例:Undo/Redo)。 -
責任の連鎖(Chain of Responsibility)
複数の処理オブジェクトが順番にリクエストを処理(例:ログ処理、承認フロー)。 -
テンプレートメソッド(Template Method)
アルゴリズムの骨格を定義し、詳細はサブクラスに任せる。 -
ステート(State)
オブジェクトの状態によって振る舞いを切り替える(例:注文状態)。 -
ビジター(Visitor)
データ構造を変えずに新しい操作を追加可能。 -
メディエータ(Mediator)
オブジェクト同士のやり取りを仲介者が管理して依存を減らす。 -
イテレータ(Iterator)
集合要素を順にアクセス(内部構造を隠蔽)。 -
インタプリタ(Interpreter)
言語の文法を解釈する(例:正規表現)。 -
メメント(Memento)
オブジェクトの状態を保存・復元(例:ゲームのセーブデータ)。
3. デザインパターン速習図
4. いつデザインパターンを使うべきか?
-
同じような設計課題に何度も遭遇する時
-
コードが重複・肥大化・拡張困難になった時
-
チーム内で共通言語として設計を共有したい時
⚠️ 注意点
-
乱用しないこと:目的は問題解決であって「パターンを使うこと」ではない
-
まず要件ありき:必要性がなければ導入しない
5. 学習のコツ
-
意図を理解する:そのパターンはどんな問題を解決するか?
-
例を見る:現実のユースケースで理解する
-
プロジェクトで実践:小さく取り入れて試す
-
振り返り:利点・欠点を整理して学びにする