Design Patterns of the Visitor Pattern (Visitor Pattern) Introducing the Visitor PatternVisitor Pattern ExamplesVisitor Pattern Analysis
Visitor means visitor. The data structure holds the elements. Generally we need to process the elements, so where do we put the code to process the elements? The most obvious way to do this is to put it in the class of the data structure and add methods to the class for processing. But with a lot of processing, it's more problematic, and every time a processing is added, we have to go and modify the class that represents the data structure. The visitor pattern is used to solve this problem. The visitor pattern separates the definition of data structures from their processing. That is, a new visitor class will be added, giving the processing of data elements to the visitor class, so that when new processing is to be added later, only the visitor will be added.
We will combine the composite pattern in this example [http://www.jianshu.com/p/685dd6299d96] Adding and changing on top of the example in , the folder and file represent the data structure we want to access, and then we implement the visitor to output the contents of the folder and file.
Let's see first.Class diagram.
image.png
We see that for that part of the data structure there is an interface element, this interface is used to accept visitors to an interface, which has only one method is to accept a visitor, and then subclass the specific data structure to go back and implement this this method.
package Visitor; public interface Element { public abstract void accept(Visitor v); }
Then the visitor has an abstract class that can inherit this method added according to the different types of access handling, here the visitor can also be implemented with an interface the author believes.
package Visitor; public abstract class Visitor { public abstract void visit(File file); public abstract void visit(Directory directory); }
The accessor defines two abstract methods for accessing the file class and the directory class, respectively
Next, look at the specific visitor implementation.
package Visitor; import java.util.Iterator; public 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 it = directory.iterator(); while (it.hasNext()) { Entry entry = (Entry)it.next(); entry.accept(this); } currentdir = savedir; } }
Here's the specific processing logic code.
The file and directory classes need to implement the element interface and implement the accpet method is to accept a visitor object and call the visitor object to access itself
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; } public void accept(Visitor v) { v.visit(this); } }
package Visitor; import java.util.Iterator; import java.util.ArrayList; public class Directory extends Entry { private String name; // Documents private ArrayList dir = new ArrayList(); / / Speculum public Directory(String name) { // English (name) this.name = name; } public String getName() { // The latest version of the CRM service return name; } public int getSize() { // The size of the CRM int size = 0; Iterator it = dir.iterator(); while (it.hasNext()) { Entry entry = (Entry)it.next(); size += entry.getSize(); } return size; } public Entry add(Entry entry) { // Speculum dir.add(entry); return this; } public Iterator iterator() { // Iterator return dir.iterator(); } public void accept(Visitor v) { // License keyword v.visit(this); } }
package Visitor; import java.util.Iterator; public abstract class Entry implements Element { public abstract String getName(); public abstract int getSize(); public Entry add(Entry entry) throws FileTreatmentException { throw new FileTreatmentException(); } public Iterator iterator() throws FileTreatmentException { throw new FileTreatmentException(); } public String toString() { return getName() + " (" + getSize() + ")"; } }
Finally, the test.
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 entries..."); 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 (FileTreatmentException e) { e.printStackTrace(); } } }
Test results.
image.png
Let's analyze the processing flow of the visitor pattern example program, assuming a folder with two files
Role in visitor mode.
Class diagram.
image.png