• Introducing the Visitor pattern
  • An instance of the visitor pattern
  • Visitor Pattern Analysis

Introducing the Visitor pattern

Visitor means Visitor. Data structures hold elements. Normally we need to process elements, so where is the code to process elements? The most obvious method is to put it in the class of the data structure and add processing methods to the class. But if we have a lot of processing, it’s a little bit more cumbersome, because every time we add a processing, we have to modify the class that represents the data structure. The visitor pattern solves this problem by separating the definition and processing of data structures. That is, the class that will add a visitor, leaving the processing of the data elements to the visitor class, so that when you need to add new processing, you only need to add visitors.

An instance of the visitor pattern

In this instance we will combine the composite pattern [http://www.jianshu.com/p/685dd6299d96] instance change, on the base of folders and files said we want to access the data structure, and then we implement the visitor will output the contents of folders and files.

Take a look at the class diagram:

We see that for the data structure section there is an interface element, which is an interface that accepts visitors, and there is only one method that accepts a visitor, and then subclasses that data structure to implement this method.

package Visitor;

public interface Element {
    public abstract void accept(Visitor v);
}
Copy the code

The visitor then has an abstract class, which can be added by inheriting this method depending on the type of access processing, and the visitor here can also be implemented with an interface.

package Visitor;

public abstract class Visitor {
    public abstract void visit(File file);
    public abstract void visit(Directory directory);
}
Copy the code

The visitor defines two abstract methods to access a file class and a directory class

Let’s 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; }}Copy the code

Here is the concrete processing logic code.

The File and Directory classes need to implement the Element interface and implement the AccPET method by taking a visitor object and calling 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() {
        returnsize; } public void accept(Visitor v) { v.visit(this); }}Copy the code
package Visitor; import java.util.Iterator; import java.util.ArrayList; public class Directory extends Entry { private String name; Private ArrayList dir = new ArrayList(); // 鏂 huhuan tanyi 悕 ying� private ArrayList dir = new ArrayList(); // 鐩綍𨱒 $juboard 悎 public Directory(String name) {// 鏋勯� da Dali � this. Name = nam } public StringgetName{// Luanfeng 彇 tin 嶅瓧return name;
    }
    public int getSize() {                  // 鑾峰彇澶у皬
        int size = 0;
        Iterator it = dir.iterator();
        while (it.hasNext()) {
            Entry entry = (Entry)it.next();
            size += entry.getSize();
        }
        returnsize; } public Entry add(Entry Entry) {// touch 鐩綍𨱒 $judir. Add (entr)return this;
    }
    public Iterator iterator() {// 熸 yao Iteratorreturndir.iterator(); } public void Accept (Visitor V) {// 鎺 infectivity keys keys pop monkeys V. V. Smithit (this); }}Copy the code
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() + ")"; }}Copy the code

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(); }}}Copy the code

Test results:

Analysis of Visitor Pattern

Let’s examine the flow of the visitor pattern sample application, assuming that there are two files in a folder

  • First, the main class generates the listVisitor instance.
  • The Main class calls the directory method and passes in the generated listVistor instance
  • Directory’s Accept method calls the visitor’s processing method and passes in an instance of itself.
  • Next, we come to the listVIsitor process, access the folder, and then find the first file in the folder, call accPET on that file, and pass in an object that is its own listVIsitor instance
  • It’s a recursive process, and the listVisitor will go and process the file, and then when it’s done it will return something like a stack
  • It then goes back to the directory processing, and then to the second file, repeating the process until there are no objects left to process.

Roles in visitor pattern:

  • The visitor role is responsible for declaring a corresponding visit method for each concrete element in the data structure. The concrete implementation is handed to the ConcreteVisitor

  • The ConcreteVisitor is responsible for inheriting the method that implements the visit handling of the visitor, implementing the concrete processing logic

  • Element represents the object visited by the visitor and declares the Accept method that accepts the visitor.

  • ConcreteElemnet is responsible for implementing concrete elements, file and Directory classes in instances

  • ObjectStructure is responsible for processing the collection of Elemnet elements. Each Elemnet implements the method of receiving visitors. Therefore, in order to access all elements, a collection structure of all elements needs to be stored, and directory in the instance corresponds to this.

Class diagram: