GoFの23パターンについて
原則
- 変わるものを変わらないものから分離する
- インターフェイスに対してプログラミングし、実装に対して行わない
- 継承より集約
- 委譲、委譲、委譲
- 必要になるまで作るな(You Ain’t Gonna Need It./YAGNI)
振る舞いに関するパターン
ChainOfResponsibility パターン
http://www.techscore.com/tech/DesignPattern/ChainOfResponsibility.html/
http://www.ie.u-ryukyu.ac.jp/~e085739/java.it.15.html
責任者が連鎖するように実装。
呼び出し時に、責任者を設定する。
オブザーバーパターンと近い?
使いどころ
モデル生成時に、内部クラスを切り分けたい時など(chainする必要ない?)
Rubyではあまり仕様しない
注意点
chainするので、深い実装をする場合は処理速度に注意。
Command パターン
http://www.ie.u-ryukyu.ac.jp/~e085739/java.it.16.html
命令を実行する。
特定の処理(コマンド)を別のオブジェクトに分離する。これはコードブロックでも代用ができる。
処理は複数まとめて実行したり、元の状態に戻すこともできる。
使いどころ
処理を特定のオブジェクトから分離する場合に用いる。
具体例
ActiveRecordのマイグレーションはモデルとは分離された処理になっており、ロールバックも実装することができる。
Interpreter パターン
専用の言語で組み立てる。
要点
プログラム言語では実装しにくい(非常に大変な)処理を、簡単に行えるようにするためのAPIを提供する。
さらにパーサを作ることで、プログラム言語の文法とは全く関係ない別の言語を作ることができる。
使いどころ
使用範囲が明確であり、何度もあるいは多くの人がそれを使う必要があり、より簡単に使うための機能を提供したい場合。ただし、RubyはDSLを作ることができるので、多くの場合はDSLを使ったほうが問題を容易に解決できる。
具体例
Rubyそのものは、C言語で作られたインタープリタ型言語である。
SQLや正規表現などもインタープリターの一種。
Iterator パターン
http://www.ie.u-ryukyu.ac.jp/~e085739/java.it.17.html
http://morizyun.github.io/blog/ruby-design-pattern-05-iterator/
集合体があった場合に、繰り返し処理を別クラスに移譲する。
集約オブジェクトの内部表現を公開せずに、その要素に順次アクセスする場合に用いる。
each
each_with_index
each_index
reverse_each
each_with_object
map
lambda = -> (str) { str.upcase }
%w(hoge fuga piyo).map(&lambda)
使いどころ
繰り返し処理を行うところ。
具体例
オブジェクトの要素に順番にアクセスする
Mediator パターン
http://www.ie.u-ryukyu.ac.jp/~e085739/java.it.18.html
http://www.techscore.com/tech/DesignPattern/Mediator.html/仲介役のオブジェクトを介して処理を行う。
使いどころ
オブジェクトが大量にあり、処理を集約したいとき
Memento パターン
http://www.ie.u-ryukyu.ac.jp/~e085739/java.it.19.html
http://www.techscore.com/tech/DesignPattern/Memento.html/
変化する状態の復元
使いどころ
cacooみたいなサービスを作りたい時に、戻したい時とか
Observer パターン
http://www.ie.u-ryukyu.ac.jp/~e085739/java.it.20.html
http://www.techscore.com/tech/DesignPattern/Observer.html/
変更があった場合は通知する。
- あるオブジェクト(サブジェクト)の値に変更があった時に、変更を検知したい全てのオブジェクト(オブザーバ)に対して、オブザーバ側のメソッドを通じて通知する。
- サブジェクト側に必要なメソッドはモジュール化して、サブジェクトのクラスにincludeすると良い。Rubyの標準ライブラリにObservableモジュールがあるのでそれを使うことができる。
あるオブジェクトの状態が変わった時に、他のオブジェクトに変更を通知したい場合。
使いどころ
非同期処理の結果を受け取る時。
State パターン
http://www.techscore.com/tech/DesignPattern/State.html/
オブジェクトの状態を考慮する
#### 使いどころ
オブジェクトの状態により、実行するメソッド・結果を変えたい時
Strategy パターン
アルゴリズムを交換する。
- Template Methodパターンと同様の問題(一部が異なる処理が複数ある)を委譲によって解決する。
- 処理が異なる部分を別のオブジェクトに委譲して分離する。委譲したクラスをストラテジといい、ストラテジを使う側のクラスをコンテキストという。
- このパターンではコンテキストからストラテジにデータを渡す手段が必要になる。方法としては2つあり、1つめは必要なデータだけをストラテジのメソッド引数に渡す。2つめはコンテキスト自身のインスタントをストラテジのメソッド引数に渡す。ただし後者はコンテキストとストラテジが密結合になる。
- ストラテジの処理が1つだけなら、ストラテジの代わりにProcオブジェクトにしてもよい。
使いどころ
TemplateMethod パターン
スーパークラスで処理の枠組みを定め、サブクラスでその具体的内容を定めるようなデザインパターン
RubyにはAbstractが存在しない。ついでに型も存在しない。
Templateパターンの目的は「インタフェースと実装の分離」
Rubyではあるメソッドを実装していることがインタフェースなので(duck typing)、Template Methodパターンの適応は難しい。
全体の流れは同じである複数の処理があり、一部の処理を変更する必要がある場合。
委譲にすることでクラス間の結びつきを疎結合にしたい場合。
Visitor パターン
処理をvisitorとして分けることで、追加を簡単に
http://www.techscore.com/tech/DesignPattern/Visitor.html/
J2EEパターン
プレゼンテーション層のパターン
ViewHelper(ビューヘルパ) ビューからロジックを分離する
ビジネス層のパターン
Session Facade
(セッションファサード) ビジネスロジックの複雑さを隠して、
シンプルな入り口を作る
インテグレーション層のパターン
Dao(Data Access Object) データアクセスを抽象化する
DSL
最後に
Javaでデザインパターンを実装するためには様々な役割を持つオブジェクトを生成しますが、
rubyishに書くならば、役割を担うオブジェクトをいくつも生成するよりオープンクラスなどの言語機能を用いるほうが筋が良さそうだと感じました。