当記事ではJavaScriptデザインパターンを参考文献として、JavaScriptのデザインパターンについて学んだ内容を記載しています。
前提
- 2013年の書籍のため、ES5以前のJavaScriptについて解説している。
- 現行仕様(ES2015以降)で言語仕様として解決された内容もあるので注意。
パターンとは
ソフトウェア設計にあたり、普遍的に生じる問題を解決するのに便利な使いまわしできる解決策のこと
理解し、慣れることが大切である理由として次の3つが挙げられる。
- パターンは実績のある解決策である
- パターンは簡単に再利用できる
- パターンは表現力が豊かである
パターンは解決策そのものではなく「解決策を考える枠組み」である。
パターン採用の利点
- パターンの再利用によって、開発上の大問題に発展する可能性のある小さな問題を未然に防ぐ
- パターンは一般化された解決策であるため、1つの問題に限らず、さまざまな問題に幅広く応用できる
- パターンを利用すると、繰り返しを防ぐことでコード全体量を減らせる傾向がある。
- パターンがもたらす語彙によって開発者のコミュニケーションが円滑になる
- 使用頻度の高いパターンは、そのパターンを利用した開発者たちの経験をフィードバックさせることで改良できる
「良い」パターン
下記の条件を満たしたものが「良い」ものとされている
- 特定の問題を解決する
- 明確な解決策を持たない
- 実績のある概念を表現する
- 関係性を表現する
条件を満たしていないものは「プロトパターン」と呼ばれ、採用するにあたり投機的なパターンとなる
そのパターンが「妥当である」と判斷される基準
パターンを妥当なものとするためには「3の法則」をチェックすることで再現性がわかる
- 目的の適合度 - そのパターンはどれくらい効果的だと考えられているのか
- 実用性 - そのパターンはなぜ効果的だと考えられているのか
- 適用可能性 - そのデザインは広範囲に適用でき、パターンにする価値があるのか。そうであるならば根拠の説明が必要
デザインパターンの構造
パターンは規則として表され、下記のものとの関係が明示される。
- 文脈
- 文脈の中で生じる要因の体系
- それらの力が文脈の中で自らを解決させる構成
デザインパターンに含まれる要素
- パターン名 : パターンの名前
- 説明 : そのパターンの簡潔な説明
- 文脈 : パターンがユーザ要求に効果的に応えることのできる文脈
- 問題 : パターンの意図を理解できるように、対処する問題を説明する
- 解法 : ユーザの問題をどう解決するか、手順と知見のわかりやすい一覧で説明する
- デザイン : パターンのデザインの説明。特にユーザがパターンを使ってどう行動するかについて説明する
- 実装 : パターンの実装方法の方針
- 図 : パターンのクラスを視覚的に説明する(ダイアグラムなど)
- 例 : 最小限の形式でのパターンの実装
- 前提条件 : 説明されているパターンを利用するためには、和歌にどうなパターンが必要となるか
- 関連事項 : このパターンに似ているのはどんなパターンか。他のパターンを似せているのか
- 知られている使用方法 : パターンは世の中で使われているか。もし使われているならば、どこで、どうやって使われているか
- 議論 : パターンの利点に関する作者の考え
デザインパターンを作成する
デザインパターンの構造を理解して、作成する方法を知ることで、
デザインパターンが「何であるか」を学び、利用する際にも深い知見を得ることができる。
デザインパターンを作成する際は下記を心がけること
- どのくらい実用的か
- ベストプラクティスを忘れずに
- デザインパターンはユーザーに影響を与えてはならない
- 独創性はデザインパターンを作るうえで重要ではない
- デザインパターンにはわかりやすい使用例が必要である
GoFが言及する23のデザインパターン
- 生成に関するもの
- 構造に関するもの
- 振る舞いに関するもの
生成に関するもの
特定の状況下で適切な方法によってオブジェクトを生成する仕組みに着目している。
基本的なオブジェクト作成方法を利用すると複雑さが増すことがあるが、デザインパターンでオブジェクト作成の過程を制御することで、この問題を解決する。
クラス構造
- ファクトリメソッド : 渡されたデータ・イベントを元に派生クラスのインスタンスを作成する
オブジェクト構造
- 抽象ファクトリ : 具象クラスの細部を明らかにせずにクラスのインスタンスを作成する
- ビルダー(コンストラクタ) : オブジェクトの作成過程を表現形式と切り離す。常に同じタイプのオブジェクトを生成する
- プロトタイプ : コピーの際に、完全に初期化されたインスタンスを利用する
- シングルトン : グローバルからアクセスできるインスタンスがひとつしかないクラス
構造に関するもの
オブジェクトの合成に関するものであり、異なるオブジェクト間の関係性をわかりやすくするために使われている。
これを利用すると、システムの一部を変更してもシステム全体を変更せずに済むようになる。
また、システムの一部が目的に合わないときにその部分を作り直す際にも役立つ。
クラス構造
- アダプタ : 異なるクラスのインターフェイスを対応させて、インターフェイスが対応していないクラス同士でも組み合わせて使えるようにする
オブジェクト構造
- アダプタ : 異なるクラスのインターフェイスを対応させて、インターフェイスが対応していないクラス同士でも組み合わせて使えるようにする
- ブリッジ : オブジェクトのインターフェイスを実装から切り離し、インターフェイスと実装をそれぞれ独自に変更できるようにする
- コンポジット : 個々のオブジェクトとオブジェクトを合成したものの構造を一様に扱うことで、別々に扱うよりも多くのことができる。
- デコレータ : オブジェクトに動的に処理を追加する
- ファサード : 1つのクラスがサブシステム全体の複雑性を隠蔽する
- フライウェイト : いたるところで使われている情報を効率的に共有するために、小さなサイズのインスタンスを利用する
- プロキシ : 本物のオブジェクトの代わりとなる代理オブジェクト
振る舞いに関するもの
システム内の異なるオブジェクト間の通信を改善して簡素化することに着目している。
クラス構造
- インタプリタ : アプリケーションに言語要素を追加し、対象とする言語の文法に対応する
- テンプレートメソッド : メソッド内にアルゴリズムの塊を作り、サブクラスへのステップを遅延させる
オブジェクト構造
- 責任の連鎖パターン : 一連のオブジェクトの中でリクエストを順番に渡していき、その要素を対処できるオブジェクトを見つける方法
- コマンド : コマンドの実行動作をコマンドを発行する立場から切り離す
- イテレータ : コレクションの内部動作について知ることなく、そのコレクションの要素に順番にアクセスしていく
- メディエータ : クラス間のやり取りを簡素化し、クラス同士が直接参照し合うのを防ぐ
- メメント : オブジェクトの内部状態を記録し、後でそれを復元できるようにする
- オブザーバ : 変更をたくさんのクラスに通知し、クラス感の一貫性を保証する方法
- ステート : 状態が変わったときにオブジェクトの振る舞いを変える
- ストラテジー : クラス内部のアルゴリズムをカプセル化し、アルゴリズムの選択をクラスの実装から独立させる
- ビジター : クラスを変更することなく、そのクラスに新たなオペレーションを追加する