GoFデザインパターン全23種の概要と利用場面
プログラミング #GoF #オブジェクト指向 #クリーンコード #デザインパターン目次 / Index
はじめに
「オブジェクト指向における再利用のためのデザインパターン(通称: GoF本)」というタイトルで紹介されている23種のデザインパターンについて、概要とそれぞれどういった場面で使用すべきか?を一覧でまとめてみました。
それぞれの実装コードなどは他サイトで詳細に解説されているため、本記事では解説しておりません。
この記事は「ここの設計、ちゃんとしておかないと後々大変になりそうだけど、どうすればいいだろう?」という時に参考となれば良いなという思いで作成しました。
設計をする際の一助となれば幸いです。
生成に関するパターン
パターン | 概要 | 利用場面 | 例 |
---|---|---|---|
Abstract Factory | 関連するオブジェクトのグループを作成するためのインターフェースを提供 |
|
マルチプラットフォームアプリでWindowsとMacOS向けのGUIコンポーネントを切り替えて使用 |
Builder | 複雑なオブジェクトの構築をシンプルにする |
|
|
Factory Method | オブジェクト作成時に、作成するオブジェクトのクラスをサブクラスに選ばせる方法 |
生成するインスタンスの種類が多くなりそうな場合に、インスタンス生成の責務を外に切り出して保守性を高めたい場合 |
ファイルの読み込み処理を行うクラスを作成し、ファイルの種類によって読み込み処理を切り替えたい場合 |
Prototype | 既存のオブジェクトをコピーして新しいオブジェクトを作成 |
抽象が同じオブジェクトの生成を簡素化し、パフォーマンスを向上させたい場合 |
オブジェクトの生成に時間がかかる場合、プロトタイプをコピーして新しいオブジェクトを生成することで、時間を短縮 |
Singleton | クラスのインスタンスが1つだけ生成されることを保証 |
生成するインスタンスが1つだけであることを保証したい場合 |
ロギングやデータベース接続などの共有リソースを1つだけ持ちたい場合 |
構造に関するパターン
パターン | 概要 | 利用場面 | 例 |
---|---|---|---|
Adapter | 互換性のないインターフェースを持つクラス同士を協調させるためのパターン |
|
外部ライブラリを既存のシステムに適合させる |
Bridge | 機能と実装を分離し、それぞれを独立して変更可能にするパターン |
クラス継承が複雑になり、継承の深さが増える場合 |
– |
Composite | オブジェクトを木構造で構成し、個別のオブジェクトと複合オブジェクトを同じように扱うためのパターン |
|
ファイルシステムのディレクトリやファイルを扱う際に、ディレクトリとファイルを同じように扱いたい場合 |
Decorator | 既存のオブジェクトに動的に新しい機能や振る舞いを追加するためのパターン |
|
サードパーティライブラリの機能拡張 |
Facade | 複数のクラスやモジュールの複雑な相互作用を隠蔽し、シンプルなインターフェースで提供するためのパターン |
|
– |
Flyweight | 多数の同様なオブジェクトを生成する際に、共通部分をキャッシュしてメモリ使用量を削減するパターン |
重複した部分を持つ類似したオブジェクトを大量に生成する際に、一部を再利用することでメモリ効率を向上させたい場合 |
–
|
Proxy | 他のオブジェクトへのアクセスを代理するためのパターン |
オブジェクトへのアクセスを制御し、 元のオブジェクトへリクエストが行く前か後に別の何か(アクセス制御やキャッシュ、ロギングなど)を行えるようにしたい場合 |
– |
振る舞いに関するパターン
パターン | 概要 | 利用場面 | 例 |
---|---|---|---|
Chain of Responsibility | 要求を処理できる可能性のある複数のオブジェクトを連鎖させ、要求を連鎖に沿って渡していくパターン |
「この要求はこのオブジェクトが処理する」ということが決められない or 複数のオブジェクトが処理する可能性がある場合 |
– |
Command | 処理をリクエストするクラスと、処理を実行するクラスを分離するパターン |
|
– |
Interpreter | 構文規則を持った文字列を解析し処理するためのパターン |
何らかの構文規則を持った文字列(CSVなど)をプログラムで解析・表現したい場合(いわゆるDSL) |
– |
Iterator | 配列のような集約に対し、順番にアクセスする方法を提供するパターン |
|
– |
Mediator | 複数のオブジェクト間の通信を直接行うのではなく、mediatorオブジェクトを介して行うことで、オブジェクト間の結合度を低くするパターン |
複数オブジェクトからの問い合わせを受け、適宜判断を行い、オブジェクト全体、もしくは、一部のオブジェクトに指示を出したい場合 |
複数のユーザー間のメッセージのやり取りを管理したい場合 |
Memento | オブジェクトの内部状態を保存し、後でその状態に復元できるようにするパターン |
オブジェクトの状態を保存・復元する必要がある場合 |
テキストエディタの「元に戻す」機能 |
Observer | インスタンスの変化を他のインスタンスから監視できるようにするパターン |
オブジェクトの状態が変化した際に、他のオブジェクトに通知を行いたい場合 |
ユーザーが新しい投稿をした際に、フォロワーに通知 |
State | オブジェクトの状態に応じて振る舞いを変えるためのパターン |
状態に応じて異なる振る舞いをするオブジェクトがあり、状態の種類が多く、状態固有のコードの変更が頻繁だったり、複雑な場合 |
自動販売機オブジェクトで、商品の在庫状況や投入金額によって、振る舞いが変化する |
Strategy | アルゴリズムをインターフェースでカプセル化し、アルゴリズムを容易に切り替えられるようにするパターン |
アルゴリズムを切り替える必要がある場合 |
支払い方法の選択で、クレジットカード、PayPal、銀行振込など、異なる支払い方法を実装する |
Template Method | スーパークラスで処理の枠組みを定め、サブクラスでその具体的な内容を実装するパターン |
複数のクラスで共通の処理を持つ場合 |
ファイルの読み込み処理を実装する際、ロガーなど基本的な部分は共通だが、ファイルの種類によって一部の処理が異なる場合 |
Visitor | データ構造と処理を分離するパターン | データ構造の中に様々な要素があり、それぞれに対して異なる処理を行いたい場合 | Validate処理でデータ構造特有のValidate処理を行いたい場合 |
最後に
これらのデザインパターンは絶対に使用しないといけないという訳ではありません。適用出来そうだからと無理に組み込んでも逆に負債になる場合もあります。
将来を考え「どういう負債や問題が起こりそうか?」「どういったニーズが起こりそうか?」と自問し、「デザインパターンを適用したほうが保守しやすいな」と考えが定まったら適用していくと良さそうです。