はじめに
Java言語で学ぶデザインパターン入門を読んでみたのですが、そのまま読んだだけだと内容が頭に入ってこなかったので、学習のコツだったり、勉強してまとめた結果だったりを記事にしてみました。
学習のコツ
GoFの23のデザインパターンを,Javaで活用するための一覧表 (パターンごとの要約コメント付き)
↑こちらのサイトをかなり参考にさせていただきました。
特に重宝したのがレベル別の4分類。
「どこから手をつけたら良いのか分からない。」「こんなパターン本当に使うの?」と思っていた自分にとっては、学習の優先順位がついたおかげでかなり捗るようになりました。
学習の優先順位×パターンの目的を表にしたものがこちらです。
プログラミングのセンスがあれば,言われなくても自然に使うもの | パターンの名前自体が有名で,あちこちで使われているもの | 独力で思いつくのは困難だが,一度ちゃんと学べば,驚くほどプログラミングが開眼するもの | メリットがわかりづらく,使われづらいもの | |
---|---|---|---|---|
生成 | ・Builder:初期化手順を細分化 | ・Factory Method:動的にサブクラス選択 ・Singleton:1インスタンスを保証 |
・Abstract Factory:工場の工場 ・Prototype:コピーを渡す |
|
構造 | ・Adapter:継承/委譲でラッパー ・Decorator:委譲で意図的フック ・Facade:複数クラス利用手順書 |
・Proxy:こっそりフック | ・Bridge:拡張と実装の階層分離 ・Composite:再帰ツリー構造 |
・Flyweight:キャッシュ付の工場 |
振る舞い | ・Template Method:子が処理断片を具体化 ・Strategy:アルゴリズム切り替え ・Mediator:スター状の相互作用 |
・Observer:イベントリスナ ・Iterator:並んだ物を順番に処理 |
・State:状態オブジェクト ・Command:タスクキューとスタック ・Memento:状態のゲッタとセッタ ・Interpreter:独自言語の実行 ・Chain of Responsibility:助け船ネットワーク ・Visitor:構造の便利スキャナ |
私はこれを左側から順に片付けていきました。スッと頭に入ってくる&どこかで見覚えがあるパターン→複雑&馴染みのないパターンとグラデーションしていったので、非常に学習しやすかったです。
また、「パターンの目的」のどれに該当するのか(生成/構造/振る舞い)、という部分も意識すると、今自分が何をやっているのか見失わないので良いです。
各パターンのまとめ
・端的に言うとこれはどういうパターンなのか?
・このパターンはどういう場面で使うものなのか?どんなメリットがあるのか?
という2軸で、各パターンについてまとめてみました。
プログラミングのセンスがあれば,言われなくても自然に使うもの
端的に言うと? | いつ使うの?どんなメリットがあるの? | |
---|---|---|
Builder | 処理フローと具体的な処理の分離 | ユースケース層とインフラ層の接続(依存性逆転) |
Adapter | ラッパークラス | 腐敗防止層 |
Decorator | コアと追加機能の同一視による機能カスタマイズ | 追加機能の組み合わせ次第で無限のバリエーションを生み出せる |
Facade | 窓口となるAPIを提供 | 処理の隠蔽 |
Template Method | 継承 | 処理の隠蔽 |
Strategy | アルゴリズムの分離 | アルゴリズムを切り替えられる |
Mediator | 複数クラス連携を中央集権管理 | クラス間の相互作用が整理される(交通整備) |
パターンの名前自体が有名で,あちこちで使われているもの
端的に言うと? | いつ使うの?どんなメリットがあるの? | |
---|---|---|
Factory Method | 抽象クラス側でインスタンス生成と利用のメソッドを定義 | フレームワークと実装の分離 |
Singleton | 1インスタンスを保証 | 1インスタンス前提で副作用を考慮した実装ができる |
Proxy | 重い処理を肩代わり | レイジーロード的なことができるようになる |
Observer | クラスの状態変化を通知して処理 | 非同期処理(Pub-Sub)ができるようになる |
Iterator | 集合要素を順次処理 | 順次処理の分離/定型化 |
独力で思いつくのは困難だが,一度ちゃんと学べば,驚くほどプログラミングが開眼するもの
端的に言うと? | いつ使うの?どんなメリットがあるの? | |
---|---|---|
Bridge | 拡張と実装の階層分離 | 移譲/継承の意味をレイヤーごとに分けて考えることができる(基礎↔︎拡張/抽象↔︎実装) |
Composite | 入れ物と中身の同一視による再帰ツリー構造 | 再帰構造(木構造)の実現 |
State | 状態をクラスで表現し、切り替えて(状態遷移して)使用する | if文やswitch文による条件分岐が不要になる |
Command | 命令をオブジェクトとして表現し、execute()で実行できるようにする | キューやスタックを活用することでタスクを柔軟に管理/実行できる |
Memento | 状態の保存と復元 | カプセル化を壊さずに状態へのアクセス(取得/更新)ができる |
Interpreter | 独自言語の構文解析 | 独自言語(BNFによる定義)をクラスに落とし込み構文解析/実行をすることができる |
Chain of Responsibility | 処理担当者の連鎖を構築する | 連鎖を組み替えることで柔軟な処理を表現できる 自分の仕事に集中できる(連鎖の他の要素が何を担っているのか気にしなくて良い) |
Visitor | データ構造を渡り歩いて仕事をする | データ構造から処理を分離できる |
メリットがわかりづらく,使われづらいもの
端的に言うと? | いつ使うの?どんなメリットがあるの? | |
---|---|---|
Abstract Factory | 抽象クラス側で構造全体のインスタンス生成と利用のメソッドを定義 | フレームワークと実装の分離 |
Prototype | 登録したインスタンスをclone()でコピーして渡す | インスタンス生成を隠蔽し、クラス名(new句)の制約から解放する |
Flyweight | 一度作ったインスタンスをプールして使い回す | メモリ使用量を抑えられる |
おわりに
デザインパターンの勉強はただやるだけでは23個のパターンの丸暗記になってしまいますが、レベル別だったり目的別にチャンクを作ることで良い学習ペースを作ることができます。
また、デザインパターンは全てのオブジェクト指向プログラミングの基礎になっているものなので、同じ概念が言葉を変えて別のプラクティスで登場していたりします(例えばAdapterパターンはDDDで言う所の腐敗防止層として登場します)。
既に知っていることと関連付けて勉強すると、ただの個別事項の暗記ではなく、一つの大きな枠組みの中での関連として捉えることができるので、効率よく&知識として引き出しやすい形で定着させることができると思います。