前回の記事に続いて期間は空いてしまったんですが、何とか読みきりました。ただし途中で速度を上げざるを得なかったために一部あやふやなまま進めることに。

読みきった感想としては予想以上にパターンがパターン化していましたなぁという所に尽きます。実際に必要だろうなと思うパターンはそれほど多くなく、Java を扱っているからという事以外の原因を感じました。

取り合えず数が多いので自分がなるほどと思ったものをピックアップして纏めたいと思います。

Builer

CGI で Web ページを作成していたりする時に自然と行き着くパターン。
一つ一つのパーツで完結した結果を組み合わせる事で一つの物を作成する。

AbstractFactory

抽象的な部品を組み合わせて抽象的な全体を組み上げるパターン。
抽象クラスを継承し、親クラスによって定められたメソッド (部品) のみで具象クラスを作成する。また、その具象クラスを使用して (インスタンスを扱って) 目的の動作を行うクラスを実装する。

結構 Java ならではの考え方な気はしたんですが、API の考え方や、設計に関して割と大事な位置づけにある気がします。

Bridge

機能を保持するクラスと、実装を保持するクラスの住み分けを策定するパターン。
機能を保持するクラスとは、実装を扱う側のクラスで、実装クラスを扱うための機能を保持しています。サンプルでは Display クラスを CountDisplay クラスの二つが存在し、CountDisplay クラスは Display クラスのサブクラスでした。もちろん機能は追加されてます。

それに対し、実装を保持するクラスは道具を提供します。道具を提供するだけなので調理するのはあくまでも機能のクラスです。抽象クラスによって設計を行い、具象クラスによって実装を行う関係です。

Bridge パターンも AbstractFactory と同じで、設計時に参考になる考え方ということから書いてます。

Strategy

アルゴリズム簡単に切り替えることが出来る機能を実装するパターン。
書いてることは小難しめでしたが、要するにインターフェースを規定し、受け取る結果のフォーマットを合わせて実装するだけでした。それをインスタンスによって管理することで API は変わらず受け取る予定のデータのフォーマットも変わらないために簡単に差し替えることが出来るというわけですね。

Composit

マトリョーシカの如く再帰的にクラス構造を作成するパターン。
本書では容器と中身の同一視という説明で書かれています。再帰を使用して処理できる問題ならそれでいいのですが、再帰的に表現されている状態を保持して後で処理を行いたいという場合に便利です。

構造もシンプルで、自身のスーパークラスをインスタンス経由で扱う構造を作る程度で出来ます。後はインスタンスでラッピングしていくと構造が再帰的な状態になるというわけですね。

Visitor

Visitor パターンは Composit パターン見たいな構造を扱う時に併せて使用するパターン。
accept メソッドと visit メソッドが非常にややこしいですが、accept の用途が許可をだすだけだと分かればそれほど悩ましい物でもなかったです。ポイントは Visitor は accept された Directory に訪問し、同じクラスの次の訪問先インスタンスを作成し、そこからまた accept を行う。この繰り返しでラストの訪問先まで回すだけです。この関係が分かれば複雑さは解消されると思います。(僕はそれで納得がいきました。)

Facade

ごちゃごちゃしたインターフェースを纏め、シンプルな API を提供するパターン。
複数の使うべきクラスやメソッドを少数のメソッドに纏め直すことで、複雑な使用方法を回避できます。

一連の流れが決まってるなら特に使う意義のあるパターンかと思います。

Mediator

多くのクラスを同時に扱う必要がある時にマネージャーを用意するパターン。
GUI のプログラムが例題に使われているんですが、おそらく各コンポーネントの状態遷移が非常に煩雑になりやすいからだと思います。
部品のオブジェクト同士の通信を減らしマネージャーを介してデータをやりとりするように仕向けることで仕様変更に強い設計になるということでしょう。

Observer

状態の観測を行うパターン。と、本書では書かれていながらも実際は観測ではなく、通知待ちであるという事実。Observer はスレッドをスリープさせて待機しておき、Observer への通知を持って状態の更新を行う。こうすると更新の通知を受けたときにイベントを起こす事が出来ます。

Flyweight

同じ物を共有することでリソースの消費を抑えるパターンです。
一つの動作を行うのに必要なリソースが大きいときは、結果のみをインスタンスとして保存しておき、二度目以降の使用時には保存した物を利用する仕組み。使い終わって使用予定がない物はインスタンスへの参照を外しておかないと Java では GC が走らない点には注意。
本書ではインスタンスを Hashtable によって管理していた。

Proxy

仮のオブジェクトによって代行し、重い処理を先延ばしにするパターン。
重い処理は本当に必要なタイミングまで実行され無いように、普段の処理を Proxy オブジェクトに代行させる。パラメータの設定等を含めて時間がかかる処理は、実際に呼び出されたタイミングでオブジェクトを生成し、Proxy に使わせる。

まとめ

今回は前回の残りを入れたので、ある程度省略しても結構なボリュームになりました。全体を通してみると自分が自然と使っていたパターンも意外と多く、何となく把握するのには過去の経験は生きました。ただ、Java の本なので、Java 独特の表現方法がやはり気になる所ではあります。
逐一インターフェースや抽象クラスを作成しているのは、Java がかなり事前設計を意識した言語だということの現れなのかな? とも思います。

Ruby を普段から使っていると、これは言語の機能として提供されてるなと言うのが多く意識せずに使えている要因の一端でもありました。設計に関して今まで意識をしてこなかったので、デザインパターンを参考に、これからはより構造的なプログラムを書くように意識していきます。