woshidan's loose leaf

ぼんやり勉強しています

Visitorパターン

オブジェクト指向プログラミングでは、データ構造と処理は基本的にそれを扱うクラスの中に一緒に書きます。

ただ、そうじゃなくて、

データ構造である集合や集合の要素を扱う側が処理を知っているのではなくて、 それらを使うクラスが別個にあり、そちら側だけが処理の詳細を知っている、 データ構造を扱う側のクラスは、処理が行われる事(利用者側のメソッド名と返り値くらい)しかしらない、というものです。

というパターンです。

なんとも言いがたいけど、やたらと巨大なクラスが複数ある場合、目的事にモジュールに括り出して、 そのモジュールをincludeして利用する形に随時整理していったらすっきりする気がする。

インスタンスを使ってどう処理をするかは基本的にモジュールの方に任せておいて、例外だけincludeしたクラス側でオーバーライドする。 インスタンスで使うための細かいメソッド(たとえば、to_jsonとかね)は各クラス側で定義すると幸せになれる気がした。

includeするクラス側は、includeするモジュールでやりたいことの詳細を知らなくて、モジュールのメソッドに来てもらうだけ、みたいな感じに見えて、 考え方的に近そうだと思って書いた。

Elementインタフェースを実装するがごとく、モジュールで利用するメソッドは各クラスで実装しておく必要があるが。

基本的にRailsでいう肥大化したModelクラスを整理するときに意識すると効きそう。

Modelクラスは基本的なデータの成型法や取り出し方しか知らなくて、 そのデータをCSVにしたり、調査用、会計用にさらに集計したり、というのは、そのModelを利用したいモジュール側がやるというか。

調査用・特定目的の集計用のモジュールはそれ用のモジュールとして括り出しておくように追加して、 モデルには他からも利用されるような、モデル自身の仕事(データベースからのデータの取り出しやしまう前のバリデーション)だけを置いておくのがいいんじゃないかな。

こう書くとビジネスロジックを置くのが億劫になるけど、ビジネスロジックは他のモデルクラスでも似たようなことを始めたら、 モジュールに括り出して整理するような形で...。

なんか、各家に印鑑はあるんだけど、電機屋さん、Amazon、新聞の勧誘とか、各セールスマンに対してどういう判断をして、他にどういう書名なりをして印鑑を押すのかは、 各セールスマンの方が知っててくださいよ、じゃなきゃ嫌ですよ、みたいな感じで整理していくとよさそう、みたいな。

全部、家で1つ1つ把握して調べていたら、お母さん大変でしょ、みたいな。

うまくまとまらないけど、そう言うイメージを持つと判断しやすい気がした。

そのときに、紹介されている役割を意識するとよさそう。というか、うーんBridgeの最初の部分を思い出す部分も若干ある(全部、根っこは同じなのでそりゃそうだが)。

Visitor(訪問者)

データ構造の具体的な要素(ConcreteElement役)ごとに「XXXXを訪問した」というvisit(XXXX)メソッドを宣言する。

ConcreteVisitor(具体的訪問者)

スーパークラスで宣言したメソッドの処理を書く。Visitorが増える前で一種類しか無い場合は、ConcreteVisitorは忘れがちだけどVisitorはあんまり使わないかも...。

Element

Visitor役の訪問先を表す役。訪問者を受け入れるaccpetメソッドを書く。

ConcreteElement

訪問者を受け入れるaccpetメソッドの詳細を実装する。

ObjectStructure

Elementの集合を扱う役。たとえば、Fileとディレクトリみたいに、片方が片方の集合、みたいな場合、その集合の方を要素に分解したり等して、良きに扱えるように計らうクラス。さっきの家へのセールスマンの話だと、団地へ訪問する、家へ訪問する、を利用者側のメソッドからはよきに扱いたい、みたいな時に書く。

Rubyだと、acceptメソッドを書かなくてもモジュールをincludeしたら、visitor側のメソッドは使えてしまう(そして、そういうメソッドは得てして受け身系で表現される)ので、個々の違いを反映するためにオーバーライドの形でConcreteElement的なことは意識しても、Elementは意識しないかもな、ということを思いました。

railsだとhas_manyメソッドが宣言されている側にObjectStructureのような考えのメソッドを置く事になるのかもなぁ...。