Visitor パターンとは
アルゴリズムをオブジェクトの構造から分離するためのデザインパターンである。分離による実用的な結果として、既存のオブジェクトに対する新たな操作を構造を変更せずに追加することができる。
データ構造の中にたくさんの要素が格納されており、各要素に対して何かの処理をする必要があるとする。このときのその処理のコードはどこへ書くべきか。データ構造を表しているクラスへ処理を書いた場合、もし処理が1種類と限らなければ、新しい処理が必要になるたびにデータ構造を修正することになる。Visitorパターンではデータ構造と処理を分離する。
example
サンプルコード
訪問者が渡り歩くデータ構造として、Compositeパターン*1で登場したファイルとディレクトリで構成されたデータ構造の中を訪問者が渡り歩きファイルの一覧を表示するプログラムを作成する。
Visitor
ファイルやディレクトリを訪れる訪問者を表す抽象クラス
Element
Visitorクラスのインスタンスを受け入れるデータ構造を表すクラス
ListVisitor
Visitorクラスのサブクラスで、ファイルやディレクトリの一覧を表示するクラス
Entry
FileとDirectoryのスーパークラスとなる抽象クラス
File
ファイルを表すクラス
MyDirectory
ディレクトリを表すクラス
Main
動作テスト用
実行結果
$ php Main.php Making root entries... /root (30000) /root/bin (30000) /root/bin/vi (10000) /root/bin/latex (20000) /root/tmp (0) /root/usr (0) Making user entries... /root (31500) /root/bin (30000) /root/bin/vi (10000) /root/bin/latex (20000) /root/tmp (0) /root/usr (1500) /root/usr/yuki (300) /root/usr/yuki/diary.html (100) /root/usr/yuki/Composite.java (200) /root/usr/hanako (300) /root/usr/hanako/memo.tex (300) /root/usr/tomura (900) /root/usr/tomura/game.doc (400) /root/usr/tomura/junk.mail (500)
役割
Visitor役
データ構造の具体的な要素ごとに訪問する visit()メソッドを宣言する。サンプルコードにおけるVisitorクラス。
ConcreteVisitor役
Visitor役のインターフェースを定義する。visitXXX()メソッドを実装し、ここのConcreteElement役ごとの処理を記述する。 サンプルコードにおけるListVisitorクラス。
Element役
Visitor役の訪問先を表す役。訪問者を受け入れるaccept()メソッドを宣言する。acceptメソッドにはVisitor役が渡される。 サンプルコードにおけるElementインターフェース。
ConcreteElement役
Element役のインターフェースを実装する役。サンプルコードにおけるFile, MyDirectoryクラス。
ObjectStructure役
オブジェクト構造。Element役の集合を扱う役。ConcreteVisitor役が個々のElement役を扱えるようなメソッドを備えている。 サンプルコードにおけるMyDiretoryクラス(MyDirectoryは1人2役)。
まとめ
ダブルディパッチ
elementはvisitorをacceptし、visitorはelementをvisitしている。VisitorパターンではConcreteElement役とConcreteVisitor役の組によって実際の処理が決定する、これを一般にダブルディパッチと呼ぶ。
Open-Closed Principle
OCP。
- 拡張(Extension)については開かれている
- 修正(Modification)については閉じられている
既存のクラスを修正せずに拡張できるようにすべき、という方針。 デザインパターンの目的はこのような仕組みを提供することにある。
ConcreteVisitor役の追加は容易
新しいConcreteVisitor役を追加する際に、ConcreteElement役を修正する必要はない
ConcreteElement役の追加は困難
サンプルコードで、EntryクラスのサブクラスとしてDeviceクラスを追加したいとする。DeviceクラスはFileクラスとMyDirectory区rスの兄弟にあたる。そのとき、Viistorクラスには新しいvisitDevice()メソッドを追加する必要が生じる。そしてvisitorクラスのサブクラス全てに新たにvisitDevice()メソッドを実装しなければいけなくなる。
関連パターン
- PHP7でデザインパターン入門1/23 Iteratorパターン - Do Something
- PHP7でデザインパターン入門11/23 Compositeパターン - Do Something
- PHP7でデザインパターン入門23/23 Interpreterパターン - Do Something
- 作者: 結城浩
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2004/06/19
- メディア: 大型本
- 購入: 51人 クリック: 762回
- この商品を含むブログ (399件) を見る