Visitor模式即访问者模式
在数据结构中保存许多元素,我们会对这些元素进行处理,这时“处理”代码放在那里比较好?通常的做法是将它们放在表示数据结构中的类中。但是,如果“处理”有许多中那?这种情况下,没当增加一种处理时,我们就不得不去修改表示数据结构的类。
Visitor模式中将数据结构与处理分离开。
角色:
Visitor访问者:负责对数据结构中的每个具体元素声明一个用于访问XXXX的visitor(XXXX)方法。visitor(XXXX)用于处理XXXX的方法,负责实现该方法的是ConcreteVisitor角色,本示例中由Visitor类扮演。
ConcreteVisitor具体的访问者:负责实现Visitor角色所定义的接口ApI。它要实现所有的visitor(XXXX)方法,即实现如何处理每个ConcreteElement角色。在本示例中,有ListVisitor类扮演。
Element元素:表示Visitor角色的访问对象。它声明了介绍访问者的accept方法,accept方法接受到的参数为Visitor角色,本示例中由Element类扮演。
ConcreteElement具体元素:负责实现Element角色所定义的接口API。
Constructure对象结构:负责处理Element角色的集合。ConcreteVisitor角色为每个Element角色都准备了处理方法。
代码:
public abstract class Visitor { public abstract void visitor(File file); public abstract void visitor(Directory directory); }
public interface Element { public abstract void accept(Visitor visitor); }
public abstract class Entry implements Element { public abstract String getName(); public abstract int getSize(); public Entry add(Entry entry) throws Exception { throw new Exception("add"); } public Iterator iterator() throws Exception { throw new Exception("iterator"); } @Override public String toString() { return getName() + "("+getSize()+")"; } }
public class File extends Entry { private String name; private int size; public File(String name,int size) { this.name = name; this.size = size; } @Override public String getName() { return this.name; } @Override public int getSize() { return this.size; } @Override public void accept(Visitor visitor) { visitor.visitor(this); } }
public class Directory extends Entry { private String name; private ArrayList<Entry> dir = new ArrayList<>(); public Directory(String name) { this.name = name; } @Override public String getName() { return this.name; } @Override public int getSize() { int size = 0; for(Entry entry:dir) { size +=entry.getSize(); } return size; } public Entry add(Entry entry) { dir.add(entry); return this; } public Iterator iterator() { return dir.iterator(); } @Override public void accept(Visitor visitor) { visitor.visitor(this); } }
public class ListVisitor extends Visitor { private String currentDir = ""; @Override public void visitor(File file) { System.out.println(currentDir + "/" +file.getName()); } @Override public void visitor(Directory directory) { System.out.println(currentDir + "/" +directory.getName()); String savedir = currentDir; currentDir = currentDir + "/" +directory.getName(); Iterator iterator = directory.iterator(); while(iterator.hasNext()) { Entry entry = (Entry) iterator.next(); entry.accept(this); } currentDir = savedir; } }
public class Main { public static void main(String[] args) { try { Directory rootDir = new Directory("root"); Directory binDir = new Directory("bin"); Directory tempDir = new Directory("temp"); Directory userDir = new Directory("user"); rootDir.add(binDir); rootDir.add(tempDir); rootDir.add(userDir); binDir.add(new File("vi",1000)); binDir.add(new File("latex",2000)); rootDir.accept(new ListVisitor()); }catch (Exception ex){ ex.printStackTrace(); } } }
执行结果:
/root
/root/bin
/root/bin/vi
/root/bin/latex
/root/temp
/root/us