いつもお世話になってる上司さんに、めもりーちゃんサンタからクリスマス前倒しでこっそり街コンの案内をプレゼント。と思ったら、イケボCDなんて異なるソリューションもやってきました。さて、こみっとさんはどんなクリスマスを過ごすのかな。
(翌日「私...こんないじられキャラだっけ?」)
操作対象が操作の詳細を決められないとき、Visitor を受け入れられるようにだけしておけば、操作の詳細を除いて先に安定させてしまえる、というのがこのパターンです。やりたいことの詳細は後から別のパッケージで作ってもらうのです。やっぱりここでも DIP です。
こみっとさんはガードが固すぎて安定しちゃってるけど、夢見る乙女の心(枕元に靴下)を implements しているので、自分で自分を変えなきゃとがんばらなくても、Visitor がいれば寝ている間にうまういことやってもらえるわけです。
寝ている間にプレゼントをくれるサンタクロースはまさに Visitor パターンの典型例ですね。
サンタクロースのインスタンスは、クリスマスイブの夜に世界中の良い子のもとに訪れて、靴下にそっとプレゼントをインジェクションしては、誰にも知られず去っていきます。家に入って来たからといって、その行動に介入しないのがお約束です。夜中まで起きていて、サンタに向かって getToys()
などと言ってはダメですよ。
煙突が Visitor を受け入れる accept(Visitor v)
メソッドになります。その引数として侵入したサンタクロースが公開しているメソッドは visit(Target t)
のみ。その中で何が行われるかはサンタクロースインスタンスにおまかせです。こみっとさんが本当に望んだプレゼントを入れてもらえたのかは、...まあサンタによりますが。
こみっとさんは寝ているので、Visitor は保持されません。適用される対象から見れば、Visitor がどこに住んでいるのかは知らないけれど、どこからともなくメソッドの引数としてやってきてうまくやってくれ、return 後は靴下にプレゼントが入っているだけ。
他の振る舞いに関するパターンと違う特徴がここです。もし Visitor が関数で、対象が集合だった場合、その集合の Iterator は acccept した visitor の visit に各要素を渡します。
[1, 2, 3].map(function(n){ return n + 1; })
なんだか馴染みある形になりました。クラスとインターフェースで考えると少し依存がややこしいのですが、いろいろ端折ってすごく大雑把にいうと、まあこんな感じです。安定しているオブジェクトに、後からやりたいことをスッと与えるわけです。
ただ、サンタに何でもして欲しいからといって、オープンすぎると泥棒にやられるかもしれません。
通常の外部からのアクセスに対しては、メソッドの少ない抽象型で公開しておき、 サンタだけが通れる accept()
を通ればそこで初めて、visit()
により公開情報の多い具象型(自分とサンタしか知らない)が明かされるといったような工夫ができます。
いよいよ明日はクリスマス・イブですね。Visitor に visit してもらえるように、良い子 (優秀なプログラマー) のみんなは accept を実装して (いちいち対象を変更しなくても、操作を後で決定できる設計をして) 待っててね。