経緯
Gofのデザインパターン23種について社内で勉強したところ、「作り方はわかったけど、このパターンどこで使うんだ??」というような声がいくつか上がったのでまとめます。
また、わりと〇〇パターンと言われた時「あーはいはい〇〇パターンね。はいはい完全に把握した(どんなやつだっけ…?)」となることも多いのでメモでもあります。
詳しい実装方法などはたくさんの方が書かれていると思うので割愛します。
クラス生成系
Factory - ファクトリーパターン
大体どんなもの?何ができる?
共通したインターフェイス/抽象クラスから作られたクラスのインスタンス化を専門で行うクラスを用意する。そうすることで使う側がサブクラスを意識せずに利用できる。
どんな時に使える?
- 処理の名前は同じだが、処理内容が違うパターンがいくつかあり、条件によってインスタンス化するものを分ける場合
など
Abstract Factory - アブストラクトファクトリーパターン
大体どんなもの?何ができる?
ファクトリーのファクトリーパターン。
ファクトリークラス自体を一定の条件によって選択することができる。
どんな時に使える?
- バージョンや環境によって(微妙に?)異なるクラスを利用したい時
- 開発・本番などの環境違い、バージョン1・バージョン2等で処理を変えたい時
など
Builder - ビルダーパターン
大体どんなもの?何ができる?
あるクラスの生成条件などが状況によって異なる時、コンストラクタを長くせずにオブジェクトを生成できる。
setOptionA()->setOptionB()->...
のような感じ。オプションを後から設定させる。
これだと自由に色々なパターンを作れてしまうので、いくつかパターンが絞られる場合は、オプションを指定するだけのディレクター的クラスがあると良い。
どんな時に使える?
- コンストラクタでたくさんの引数があり、場合によっては必要のない引数がある時(=複数の組み合わせ・オプションがあるということ)
- インスタンス化時の内部状態が複数あるとき
など
Prototype - プロトタイプパターン
大体どんなもの?何ができる?
オブジェクトをクローンする処理をそのクラス自体に持たせるようにするもの
どんな時に使える?
- オブジェクトをコピーする時
- その際、privateな値までコピーしたい時
など
Singleton - シングルトンパターン
大体どんなもの?何ができる?
みんな大好きシングルトン。
グローバル変数の便利さとともに、意図した変更のみ許可できる。
どんな時に使える?
- グローバルにアクセスできる値(アプリケーション設定値など)を使用したい時
- DB接続などの共有リソースへのアクセスを制限したい時
など
クラス構造系
Adapter - アダプターパターン
大体どんなもの?何ができる?
Wrapper。
利用されているクラスのインターフェイス(またはそのクラス自体)を実装(継承)したクラスを別に作り、付け替えることで他の記述を変えずに挙動を変えるやり方。
どんな時に使える?
- クラスAの中にクラスBのインスタンスがあるとして、クラスBの挙動を変えたい場合
など
Bridge - ブリッジパターン
大体どんなもの?何ができる?
2種類(以上)の処理をいくつか組み合わせて実行する場合、拡張性を維持しつつ実装ができる。
どんな時に使える?
- 2種類(以上)のインターフェイス/抽象クラスから作られたクラスを内部でいくつか組み合わせて処理を行う場合
- 2つ(以上)の関連がある要素が存在し、それぞれ変更される可能性ががある場合
など
Composite - コンポジットパターン
大体どんなもの?何ができる?
各オブジェクトに"子を含める","全ての子を実行する"機能をつけることで、ツリー状の依存関係のオブジェクト群に対し、親だけに命令を出すだけで全ての処理が完結し、依存関係も小さくできるもの。
どんな時に使える?
- オブジェクトの依存関係がツリー状になっていて、共通して同じ処理を行いたい時
など
Decorator - デコレータパターン
大体どんなもの?何ができる?
基本となる処理に加え、状況や要求によって処理を追加していって実行したい場合。
集約を使っても実装できるが、抽象クラスを利用して行う方法。
どんな時に使える?
- 状況によって処理、状態の追加する組み合わせが必要な時
- 状況によってA処理だけでなくB処理やC処理も追加で行いたい時
など
Facade - ファサードパターン
大体どんなもの?何ができる?
複雑な処理・処理順序を綺麗にまとめられる。
やってることは一連の処理をまとめて別クラスに書き出すだけ。
どんな時に使える?
- 複雑な一連の処理がある場合
など
Flyweight - フライウェイトパターン
大体どんなもの?何ができる?
オブジェクトを大量に作るパーティクルなどの実装時、無駄なメモリ消費を削減する。
パーティクル内部の画像データなどを別に用意し、パーティクルの粒子1つ1つには紐付けだけ行うというもの。
どんな時に使える?
- パーティクルなど、類似オブジェクトを大量に作り、各オブジェクトの内部に画像などメモリ確保領域が広いものを利用する時(ゲームとか)
など
Proxy - プロキシパターン
大体どんなもの?何ができる?
キャッシュ。
毎度通信するオブジェクトなどの使用頻度を下げ、DBやサーバへの負荷を軽減させる。
どんな時に使える?
- キャッシュを使用しても処理がおかしくならない時
- 常には必要にならないが、時々実処理が必要になる時
など
実行方法系
Chain of Responsibility - 責任連鎖パターン
大体どんなもの?何ができる?
複雑な処理を順次実行していく時、次の処理ができるかどうかの判定の依存度を小さくし、各処理を細かく分割できる。
どんな時に使える?
- 複雑な処理を順次実行していく時
- 1つの処理の中で色々な種類の処理をしている時
など
Command - コマンドパターン
大体どんなもの?何ができる?
ビジネスロジックを外出しし、様々な箇所から呼ばれる処理の依存度を小さくできる
どんな時に使える?
- UIとビジネスロジックを分離する時
- 膨大なサブクラスの種類があり、部分部分では処理が共通しているものがある場合
など
Iterator - イテレーターパターン
大体どんなもの?何ができる?
リストデータの構造・保持と、検索パフォーマンス・順序を分離できる
どんな時に使える?
- 複雑な(独自の)リストデータを利用する時
など
Interpreter - インタープリターパターン
大体どんなもの?何ができる?
構文解析など。
HTMLの様に入れ子になっているものの判定・解析ができる。
どんな時に使える?
- いくつかの判定を組み合わせて行う時
- テキストを解析する時
など
Mediator - メディエーターパターン
大体どんなもの?何ができる?
複数のコンポーネントからなるグループ内で、コンポーネント間の動作を連携させることができる。
(UIでラジオボタンとテキストボックスがあり、ラジオボタンの種類に応じてテキストボックスの数を変えたり、など)
どんな時に使える?
- 複数のコンポーネント間で連動した動作をさせたい時
など
Memento - メメントパターン
大体どんなもの?何ができる?
履歴を管理し、戻る・進むを行えるようにする。
その際、カプセル化を維持しつつ管理ができる。
どんな時に使える?
- 状態の保存管理、履歴、アンドゥ・リドゥを実装したい時
など
Observer - オブザーバーパターン
大体どんなもの?何ができる?
イベント駆動、通知監視。
常に実行はせず、基本は処理待ちで、必要な時のみ処理を行える。
ある処理を起点に、関連する次の処理を特にループ監視とかを使わずに実行できる。
どんな時に使える?
- 特定の状態になった時だけに処理し、それ以外は待機しているような作りが必要な場合
- ある処理をトリガーとして別処理を行いたい場合
など
State - ステートパターン
大体どんなもの?何ができる?
状態をクラス化して外だしすることで、複雑な状態の管理・遷移を変更しやすくする
どんな時に使える?
- 状態の遷移が複雑なオブジェクトがある時
- 状態変化のSwitch文等が膨大になってしまった時
など
Strategy - ストラテジーパターン
大体どんなもの?何ができる?
アルゴリズムをクラス化して外だしすることで、状況によってアルゴリズムを変更できる
どんな時に使える?
- 状況によって全く異なる処理をさせたい場合
など
Template Method - テンプレートメソッドパターン
大体どんなもの?何ができる?
処理ステップが同じなら、テンプレートメソッドとして抽象クラスを用意し、
具象クラスで必要なところだけを実装することで、サブクラスによって挙動を微妙に変えられる
フックメソッドを使うといい。
どんな時に使える?
- 色々なフォーマットのデータ収集をする時
- 処理のステップは同じだが、状況によって処理内容を変えたい時
など
Visitor - ビジターパターン
大体どんなもの?何ができる?
いくつかサブクラスのパターンがあるオブジェクトそれぞれに対し、拡張機能的に処理を付け加えていける
ビジタークラス(拡張機能)に各パターンの挙動を書いて、さらに処理を分割できる
どんな時に使える?
- 既存クラスに新しい処理を追加したいが、役割の範疇を超えたり、実装が難しい時
- サブクラスの種類が複数あるクラス群の振る舞いを別出ししたい時
など
まとめ
「どう使えばいい?」という声が上がったのでまとめてみました。
細かい実装がわからなくても、ここから逆引きして使えそうであればパターン名で検索すると良いかもしれません。
基本はSOLID原則。パターンを使うことを目的に実装する人がいますが、逆。
実装で困って、パターンが適用できそうな時に利用してみましょう。