1.把数据结构与相关的处理分离开,另外写一个表示在数据结构内穿梭来去的主体“访客”的类,然后把处理交给这个类来进行。如此一来,如果想追加新的处理行为时,只要再建立一个新的“访客”即可。而在数据结构这边,也只要能接受来敲门的“访客”就能完成动作。
2.示例:
package com.cn.amk; import java.util.Iterator; import java.util.Vector; abstract class Visitor { public abstract void visit(File file); public abstract void visit(Directory directory); } class ListVisitor extends Visitor{ private String currentDir = ""; public void visit(File file) { System.out.println(currentDir + "/" + file); } public void visit(Directory directory) { System.out.println(currentDir + "/" + directory); String saveDir = currentDir; currentDir = currentDir + "/" + directory.getName(); Iterator<Entry> it = directory.iterator(); while (it.hasNext()) { Entry entry = (Entry)it.next(); System.out.println(this.currentDir + " hehe"); entry.accept(this); } currentDir = saveDir; } } interface Acceptor { public void accept(Visitor v); } abstract class Entry implements Acceptor{ public abstract String getName(); public abstract int getSize(); public Entry add(Entry entry) throws FileTreatmentException { throw new FileTreatmentException(); } public Iterator<Entry> iterator() throws FileTreatmentException { throw new FileTreatmentException(); } public String toString() { return getName() + "<" + getSize() + ">"; } } class File extends Entry { String name; int size; public File(String name, int size) { this.name = name; this.size = size; } public String getName() { return name; } public int getSize() { return size; } public void accept(Visitor v){ v.visit(this); }; } class Directory extends Entry { private String name; private Vector<Entry> directory = new Vector<Entry>(); public Directory(String name) { this.name = name; } public String getName() { return name; } 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 Iterator<Entry> iterator() { return directory.iterator(); } public Entry add(Entry entry) { directory.add(entry); return this; } public void accept(Visitor v){ v.visit(this); } } class FileTreatmentException extends RuntimeException { private static final long serialVersionUID = 1L; public FileTreatmentException() { } public FileTreatmentException(String msg) { super(msg); } } public class Main { public static void main(String[] args) { 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()); } }
这一示例的数据结构是文件层次结构。visitor提供对其层次的一个遍历行为。
3.另外一个例子:
package com.cn.dai; import java.util.ArrayList; import java.util.Iterator; public class Test { public static void main(String[] args) { A a1 = new A(1); A a2 = new A(2); A a3 = new A(3); A a4 = new A(4); A a5 = new A(5); A a6 = new A(6); A a7 = new A(7); a5.setArrayList(a6); a5.setArrayList(a7); a1.setArrayList(a2); a1.setArrayList(a3); a3.setArrayList(a4); a3.setArrayList(a5); a1.accept(new ListVisit()); } } abstract class Visitor { public abstract void visit(Entry entry); } class ListVisit extends Visitor{ private int total; @Override public void visit(Entry entry) { total += entry.getN(); System.out.println(entry.getN()); System.out.println("total: " + total); Iterator<Entry> it = entry.iterator(); while(it.hasNext()) { Entry en = (Entry)it.next(); en.accept(this); } System.out.println("endtotal: " + total); } } interface Acceptor { public abstract void accept(Visitor v); } abstract class Entry implements Acceptor { public abstract void accept(Visitor v); public abstract int getN(); public abstract void setArrayList(Entry n); public abstract Iterator<Entry> iterator(); } class A extends Entry{ private int n; private ArrayList<Entry> al = new ArrayList<Entry>(); public A(int n) { this.n = n; } public A(int n,A a) { this.n = n; this.al.add(a); } public int getN() { return n; } public void setArrayList(Entry n) { al.add(n); } public void accept(Visitor v) { v.visit(this); } @Override public Iterator<Entry> iterator() { return al.iterator(); } }
这一例子的数据结构是一个用ArrayList构建的树,每个节点有其值。visitor的操作时遍历整个数,求整个数的数值和。
4.为什么要搞得这么复杂:
visitor pattern的目的是要把处理从数据结构分出来。在集合元素或元素间的连结时,数据结构的地位非常重要。但是维持这个结构跟写一个以这个机构为基础的处理完全是两回事。