概要 †Eclipseのソースコード解析パーサASTParser を調べてたら、Visitorパタンが使われてたので、いままでめんどくさくってさぼってたVisitorパタンのお勉強をしました。そのメモです。 Visitorパタンは、あるモデルに対して動的にオペレーションを決定するためのパタンです。なんのこっちゃという感じですが、たとえば
などがありそうです。 サンプル †ディレクトリとファイルの話でサンプルを作ってみます。あるディレクトリ構造が与えられるので、そのディレクトリ構造というモデルに対してVisitorインタフェースの実装クラスをセットします。Visitorインタフェースには、ファイル用のvisitメソッド、ディレクトリ用のvisitメソッドが宣言されているので、それぞれのメソッドを実装すればよいという感じです。 /** * ファイルとディレクトリのインタフェース。 * * @author Masatomi KINO * @version $Revision$ */ interface Entry { /** * Visitorを受け入れるメソッド。だいたいvisitor.visit(this);みたいな処理になる。 * * @param visitor */ void accept(Visitor visitor); String getName(); } /** * ディレクトリ * * @author Masatomi KINO * @version $Revision$ */ class Directory implements Entry { private String name; private List<Entry> list = new ArrayList<Entry>(); public Directory(String name) { this.name = name; } public String getName() { return name; } public void addEntry(Entry e) { list.add(e); } public List<Entry> getFiles() { return list; } public void accept(Visitor visitor) { visitor.visit(this); // void visit(Directory directory); が呼ばれてる。 // ↓ さらに、自分が持ってるEntryたちのacceptも呼んであげる。 Iterator<Entry> e = list.iterator(); while (e.hasNext()) { Entry element = e.next(); element.accept(visitor); } } } /** * ファイル * * @author Masatomi KINO * @version $Revision$ */ class File implements Entry { private String name; public File(String name) { this.name = name; } public String getName() { return name; } public void accept(Visitor visitor) { visitor.visit(this); // void visit(File file); が呼ばれてる。 } } interface Visitor { /** * ディレクトリ構造を走査してったときに、 ディレクトリだったら このメソッドが呼ばれる * * @param directory */ void visit(Directory directory); /** * ディレクトリ構造を走査してったときに、 ファイルだったら このメソッドが呼ばれる * * @param file */ void visit(File file); } さて準備ができました。ではディレクトリ構成を作って、そこにVisitorをセットしようと思います。以下のようにしました。 class Client { public void method() { Directory directory = new Directory("ROOT"); directory.addEntry(new File("ほげ.txt")); Directory dir = new Directory("child"); dir.addEntry(new File("ふが.txt")); dir.addEntry(new File("ほげほげ.txt")); directory.addEntry(dir); // Visitorをセット。 directory.accept(new Visitor() { public void visit(Directory directory) { System.out.println(directory.getName()); } public void visit(File file) { System.out.println(file.getName()); } }); } } 実行結果は以下の通りです。 ROOT ほげ.txt child ふが.txt ほげほげ.txt まとめ †Visitorパタンを設計する側はともかくとして、使う側つまりVisitorの実装クラスを作る側は、モデル内の各要素(FileとかDirectoryとか)用のメソッド void visit(Directory directory); void visit(File file); を実装し、モデルにその実装クラスを directory.accept(new Visitor() {..... でセットしさえすれば、後は勝手にフレームワーク側が実装クラスのメソッドを呼び出してくれるんですね。 関連リンク †この記事は 現在のアクセス:4953 |