Visitorパターンとは
データ構造と処理を分離する。
データ構造を巡り歩く訪問者を表すクラスを用意し、そのクラスに処理を任せる。
データ構造側は、訪問者を受け入れてやる。
Visitor(訪問者)の役
Visitor役はデータ構造の具体的な要素(ConcreteElement役)ごとに「xxxを訪問した」という
visit(xxx)メソッドを宣言する。
visit(xxx)はxxxを処理するためのメソッドで、実際のコードはConcreteVisit役の側に書かれる。
package visitor;
public abstract class Visitor {
	public abstract void visit(File file);
	public abstract void visit(Directory directory);
}
ConcreteVisitor(具体的訪問者)の役
ConcreteVisitor役はVisitor役のインターフェースを実装する。
visit(xxx)という形のメソッドを実装し、個々のConcreteElement役ごとの処理を記述する。
package visitor;
import java.util.Iterator;
public class ListVisitor extends Visitor{
	private String currentDir = "";
	@Override
	public void visit(File file) {
		System.out.println(currentDir + "/" + file);
	}
	public void visit(Directory directory) {
		System.out.println(currentDir + "/" + directory);
		String savedDir = currentDir;
		currentDir = currentDir + "/" + directory.getName();
		Iterator<Entry> it = directory.iterator();
		while (it.hasNext()) {
			Entry entry = it.next();
			entry.accept(this);
		}
		currentDir = savedDir;
	}
}
Element(要素)の役
Element役はVisitor役の訪問先を表す役。
訪問者を受け入れるacceptメソッドを宣言する。
acceptメソッドの引数にはVisitor役が渡される。
package visitor;
public interface Element {
	public abstract void accept(Visitor v);
}
ConcreteElement(具体的要素)の役
ConcreteElement役はElement役のインターフェースを実装する役。
package visitor;
public class File extends Entry{
	private String name;
	private int size;
	public File(String name, int size) {
		this.name = name;
		this.size = size;
	}
	public String getName() {
		return name;
	}
	public int getSize() {
		return size;
	}
	@Override
	public void accept(Visitor v) {
		v.visit(this);
	}
}
package visitor;
import java.util.ArrayList;
import java.util.Iterator;
public class Directory extends Entry{
	private String name;
	private ArrayList<Entry> directory = new ArrayList<>();
	public Directory(String name) {
		this.name = name;
	}
	@Override
	public String getName() {
		return name;
	}
	@Override
	public int getSize() {
		int size = 0;
		Iterator<Entry> it = directory.iterator();
		while (it.hasNext()) {
			Entry entry = (Entry) it.next();
			size += entry.getSize();
		}
		return size;
	}
	public Entry add(Entry entry) {
		directory.add(entry);
		return this;
	}
	public Iterator<Entry> iterator() {
		return directory.iterator();
	}
	public void accept(Visitor v) {
		v.visit(this);
	}
}
ObjectStructure(オブジェクト構造)の役
ObjectStructure役はElement役の集合を扱う役。
ConcreteVisitor役が個々のElement役を扱えるようなメソッドを備えている。
この役は上記のDirectoryクラスが該当する。
呼び出し元
package visitor;
public class Main {
	public static void main(String[] args) {
		try {
			System.out.println("Making root entries...");
			Directory rootDir = new Directory("root");
			Directory binDir = new Directory("bin");
			Directory tmpDir = new Directory("tmp");
			Directory usrDir = new Directory("usr");
			rootDir.add(binDir);
			rootDir.add(tmpDir);
			rootDir.add(usrDir);
			binDir.add(new File("vi", 10000));
			binDir.add(new File("latex", 20000));
			rootDir.accept(new ListVisitor());
			System.out.println();
			System.out.println("Making user entryies...");
			Directory yuki = new Directory("yuki");
			Directory hanako = new Directory("hanako");
			Directory tomura = new Directory("tomura");
			usrDir.add(yuki);
			usrDir.add(hanako);
			usrDir.add(tomura);
			yuki.add(new File("diary.html", 100));
			yuki.add(new File("Composite.java", 200));
			hanako.add(new File("memo.tex", 300));
			tomura.add(new File("game.doc", 400));
			tomura.add(new File("junk.mail", 500));
			rootDir.accept(new ListVisitor());
		} catch (FileThreatmentException e) {
			e.printStackTrace();
		}
	}
}
実行結果
こちらを参考にさせていただきました。
増補改訂版Java言語で学ぶデザインパターン入門

