読み込み中...

GoFデザインパターン全23種の概要と利用場面

プログラミング #GoF #オブジェクト指向 #クリーンコード #デザインパターン
2024年7月17日
2024年7月30日
GoFデザインパターン全23種の概要と利用場面

はじめに

「オブジェクト指向における再利用のためのデザインパターン(通称: GoF本)」というタイトルで紹介されている23種のデザインパターンについて、概要とそれぞれどういった場面で使用すべきか?を一覧でまとめてみました。

それぞれの実装コードなどは他サイトで詳細に解説されているため、本記事では解説しておりません。

この記事は「ここの設計、ちゃんとしておかないと後々大変になりそうだけど、どうすればいいだろう?」という時に参考となれば良いなという思いで作成しました。

設計をする際の一助となれば幸いです。

生成に関するパターン

パターン 概要 利用場面
Abstract Factory 関連するオブジェクトのグループを作成するためのインターフェースを提供
  • 関連する複数のオブジェクトが常に一緒に使用され、整合性が保たれる必要がある場
  • 生成するオブジェクトのグループが複数存在し、それらを切り替えられるようにする必要がある場合

マルチプラットフォームアプリでWindowsとMacOS向けのGUIコンポーネントを切り替えて使用

Builder 複雑なオブジェクトの構築をシンプルにする
  • オブジェクトの構築に多くのステップが必要な場合
  • オブジェクトの生成手順を制御したい場合
  • 同じ手順で異なるオブジェクトを生成したい場合
  • 車オブジェクトの生成手順で、エンジンの設定の後にタイヤを設定するなど、順序を制御したい場合
  • プレーンテキストとHTMLという異なる形式のドキュメントを生成する場合
Factory Method オブジェクト作成時に、作成するオブジェクトのクラスをサブクラスに選ばせる方法

生成するインスタンスの種類が多くなりそうな場合に、インスタンス生成の責務を外に切り出して保守性を高めたい場合

ファイルの読み込み処理を行うクラスを作成し、ファイルの種類によって読み込み処理を切り替えたい場合

Prototype 既存のオブジェクトをコピーして新しいオブジェクトを作成

抽象が同じオブジェクトの生成を簡素化し、パフォーマンスを向上させたい場合

オブジェクトの生成に時間がかかる場合、プロトタイプをコピーして新しいオブジェクトを生成することで、時間を短縮

Singleton クラスのインスタンスが1つだけ生成されることを保証

生成するインスタンスが1つだけであることを保証したい場合

ロギングやデータベース接続などの共有リソースを1つだけ持ちたい場合

構造に関するパターン

パターン 概要 利用場面
Adapter 互換性のないインターフェースを持つクラス同士を協調させるためのパターン
  • 異なるインターフェースを持つクラスを共通のインターフェースで操作したい場合
  • 既存のクラスを再利用したいが、このインターフェースが自分のコードの他の部分と互換性がない場合

外部ライブラリを既存のシステムに適合させる

Bridge 機能と実装を分離し、それぞれを独立して変更可能にするパターン

クラス継承が複雑になり、継承の深さが増える場合

Composite オブジェクトを木構造で構成し、個別のオブジェクトと複合オブジェクトを同じように扱うためのパターン
  • 再帰的な構造を持つオブジェクトを扱いたい場合
  • オブジェクトの集合体を1つのオブジェクトとして扱いたい場合

ファイルシステムのディレクトリやファイルを扱う際に、ディレクトリとファイルを同じように扱いたい場合

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処理を行いたい場合

 

最後に

これらのデザインパターンは絶対に使用しないといけないという訳ではありません。適用出来そうだからと無理に組み込んでも逆に負債になる場合もあります。

将来を考え「どういう負債や問題が起こりそうか?」「どういったニーズが起こりそうか?」と自問し、「デザインパターンを適用したほうが保守しやすいな」と考えが定まったら適用していくと良さそうです。



システム開発やDX戦略などでお困りの際はお気軽にご相談ください。

※通常1営業日以内に回答致します。

お問い合わせはこちら
Top