In real life, some collection objects have many different elements, and each element also has many different visitors and processing methods. For example, there are multiple scenic spots and multiple tourists in the park. Different tourists may have different comments on the same scenic spot; The prescription list issued by the hospital doctor contains a variety of drug elements. The price assessors and pharmacy staff treat it differently. The price assessors price the drugs according to the name and quantity on the prescription list, and the pharmacy staff fill the drugs according to the contents of the prescription list.
There are many such examples. For example, the characters in movies or TV dramas are evaluated differently by different audiences; There are also goods that customers put in the "shopping cart" when shopping in the mall. Customers are mainly concerned about the cost performance of the selected goods, while cashiers are concerned about the price and quantity of goods.
These processed data elements are relatively stable and accessed in a variety of ways data structure , it is more convenient to use "visitor mode". Visitor mode can separate the processing method from the data structure, and can add new processing methods as needed without modifying the original program code and data structure, which improves the scalability and flexibility of the program.
Definition and characteristics of pattern
Definition of Visitor pattern: separate the operations acting on each element in a data structure and package them into independent classes, so that they can add new operations acting on these elements without changing the data structure, so as to provide a variety of access methods for each element in the data structure. It separates the data operation from the data structure. It is the most complex pattern in the behavior pattern.
Visitor pattern is an object behavior pattern. Its main advantages are as follows.
- Good scalability. It can add new functions to the elements in the object structure without modifying the elements in the object structure.
- Good reusability. Visitors can define the general functions of the whole object structure, so as to improve the reuse degree of the system.
- Good flexibility. Visitor mode decouples the data structure from the operations acting on the structure, so that the operation set can evolve relatively freely without affecting the data structure of the system.
- Comply with the principle of single responsibility. Visitor mode encapsulates the relevant behaviors to form a visitor, so that the function of each visitor is relatively single.
The main disadvantages of the Visitor pattern are as follows.
- Adding new element classes is difficult. In the visitor mode, every time a new element class is added, the corresponding specific operation must be added to each specific visitor class, which violates the "opening and closing principle".
- Destroy the package. In the visitor pattern, specific elements publish details to visitors, which destroys the encapsulation of objects.
- Violation of the dependency inversion principle. The visitor pattern relies on concrete classes instead of abstract classes.
Structure and implementation of pattern
The key to the implementation of Visitor pattern is how to separate the operations acting on elements and package them into independent classes. Its basic structure and implementation method are as follows.
1. Structure of the model
The visitor pattern contains the following main roles.
- Abstract Visitor role: define an interface for accessing concrete elements. Each concrete element class corresponds to an access operation visit(). The parameter type in the operation identifies the accessed concrete elements.
- Concrete visitor role: it implements each access operation declared in the abstract visitor role and determines what visitors should do when accessing an element.
- Abstract Element role: declare an interface containing the accept operation accept(), and the accepted visitor object is used as the parameter of the accept() method.
- Concrete element role: implement the accept() operation provided by the abstract element role. Its method body is usually visitor.visit(this). In addition, the specific element may also contain relevant operations of its own business logic.
- Object Structure role: it is a container containing element roles and provides methods for visitor objects to traverse all elements in the container. It is usually implemented by aggregate classes such as List, Set and Map.
Its structure is shown in Figure 1.
Figure 1 structure diagram of Visitor pattern( Click here to view the original image)
2. Implementation of mode
The implementation code of visitor mode is as follows:
package net.biancheng.c.visitor; import java.util.*; public class VisitorPattern { public static void main(String[] args) { ObjectStructure os = new ObjectStructure(); os.add(new ConcreteElementA()); os.add(new ConcreteElementB()); Visitor visitor = new ConcreteVisitorA(); os.accept(visitor); System.out.println("------------------------"); visitor = new ConcreteVisitorB(); os.accept(visitor); } } //Abstract Visitor interface Visitor { void visit(ConcreteElementA element); void visit(ConcreteElementB element); } //Specific visitor class A class ConcreteVisitorA implements Visitor { public void visit(ConcreteElementA element) { System.out.println("Specific visitors A visit-->" + element.operationA()); } public void visit(ConcreteElementB element) { System.out.println("Specific visitors A visit-->" + element.operationB()); } } //Specific visitor class B class ConcreteVisitorB implements Visitor { public void visit(ConcreteElementA element) { System.out.println("Specific visitors B visit-->" + element.operationA()); } public void visit(ConcreteElementB element) { System.out.println("Specific visitors B visit-->" + element.operationB()); } } //Abstract element class interface Element { void accept(Visitor visitor); } //Specific element class A class ConcreteElementA implements Element { public void accept(Visitor visitor) { visitor.visit(this); } public String operationA() { return "Specific elements A Operation of."; } } //Specific element class B class ConcreteElementB implements Element { public void accept(Visitor visitor) { visitor.visit(this); } public String operationB() { return "Specific elements B Operation of."; } } //Object structure role class ObjectStructure { private List<Element> list = new ArrayList<Element>(); public void accept(Visitor visitor) { Iterator<Element> i = list.iterator(); while (i.hasNext()) { ((Element) i.next()).accept(visitor); } } public void add(Element element) { list.add(element); } public void remove(Element element) { list.remove(element); } }
The running results of the program are as follows:
Specific visitor A accesses -- > the operation of specific element A. The operation of specific visitor A accessing -- > specific element B. ------------------------ Specific visitor B accesses -- > the operation of specific element A. Specific visitor B accesses -- > the operation of specific element B.
Application scenario of pattern
When there is a kind of data structure with a stable (fixed) number of types in the system, the visitor mode can be used to conveniently realize different operations on all data structures of this type without any side effects on the data (dirty data).
In short, the visitor pattern is used when multiple operations are performed on different types of data in the collection (the number of types is stable).
You can usually consider using the Visitor mode in the following cases.
- Object structure is relatively stable, but its operation algorithm often changes.
- The objects in the object structure need to provide a variety of different and irrelevant operations, and the changes of these operations should not affect the object structure.
- The object structure contains many types of objects. You want to perform some operations on these objects that depend on their specific types.
Mode extension
Visitor mode is a frequently used mode Design pattern , it is often used in conjunction with the following two design patterns.
(1) And“ Iterator mode ”Because the "object structure" in the visitor mode is a container containing element roles, iterators are often used when visitors traverse all elements in the container. For example, the object structure in [example 1] is implemented by List, which is implemented through the Iterator() of the List object Method. If the aggregate class in the object structure does not provide an iterator, you can also customize one with the iterator mode.
(2) The Visitor mode is the same as“ Combination mode ”Combined use. Because the "element object" in the Visitor pattern may be a leaf object or a container object, it must be used if the element object contains a container object Combination mode Its structure is shown in Figure 4.
Figure 4 shows the structure of the visitor pattern including the composite pattern
extended reading
If you want to learn more about visitor patterns, click to read the following article.
- Pseudo dynamic double dispatch in visitor mode
- Application of visitor pattern in JDK source code
- Application of visitor pattern in Spring source code