23 Design Patterns Chapter 16: Java Visitor Pattern
Definition: Encapsulates certain operations that act on each element in a certain data structure. It can define new operations that act on these elements without changing the data structure.
Type: Behavioral Pattern
Class diagram:
Visitor mode may be the most complex mode among behavioral modes, but this cannot be a reason why we don't master it.
Let's first look at a simple example, the code is as follows
class A { public void method1(){ System.out.println("I am A"); } public void method2(B b){ b.showA(this); } } class B { public void showA(A a){ a.method1(); } }Let's mainly look at what is the difference between method method1 and method method2 in class A. Method method1 is very simple, just print out a sentence "I am A"; method method2 is a little more complicated, use class B as a parameter, and call the showA method of class B.
Let’s take a look at the showA method of class B. The showA method uses class A as a parameter, and then calls the method1 method of class A. You can see that the method2 method is just calling its own method1 method. Its running result should also be "I am A". After analysis, let’s run these two methods and see the run result:
public class Test { public static void main(String[] args){ A a = new A(); a.method1(); a.method2(new B()); } }The running result is:
I'm A
I'm A
After understanding this example, you will understand 90% of the visitor pattern. In the example, for Class A, Class B is a visitor. However, this example is not the entire visitor mode. Although it is intuitive, it has poor scalability. Let’s talk about the general implementation of the visitor mode. You can see through the class diagram that in the visitor mode, the following roles are mainly included:
Abstract visitor: an abstract class or interface that declares which elements the visitor can access. Specifically in the program, the parameters in the visit method define which objects can be accessed.
Visitor: Implement the method declared by abstract visitors, which affects what visitors should do and what they should do after accessing a class.
Abstract element class: an interface or abstract class that declares which type of visitor access is accepted. The program is defined through parameters in the accept method. There are generally two types of methods for abstract elements, one is its own business logic, and the other is which type of visitors are allowed to access.
Element class: implements the accept method declared by abstract element class, usually visitor.visit(this), and basically has formed a fixed formula.
Structural object: An element container generally contains a container that accommodates multiple different classes and interfaces, such as List, Set, Map, etc. This role is rarely abstracted in the project.
Common code implementation of visitor mode
abstract class Element { public abstract void accept(IVisitor visitor); public abstract void doSomething(); } interface IVisitor { public void visit(ConcreteElement1 el1); public void visit(ConcreteElement2 el2); } class ConcreteElement1 extends Element { public void doSomething(){ System.out.println("This is element 1"); } public void accept(IVisitor visitor) { visitor.visit(this); } } class ConcreteElement2 extends Element { public void doSomething(){ System.out.println("This is element 2"); } public void accept(IVisitor visitor) { visitor.visit(this); } } class Visitor implements IVisitor { public void visit(ConcreteElement1 el1) { el1.doSomething(); } public void visit(ConcreteElement2 el2) { el2.doSomething(); } } class ObjectStruture { public static List<Element> getList(){ List<Element> list = new ArrayList<Element>(); Random ran = new Random(); for(int i=0; i<10; i++){ int a = ran.nextInt(100); if(a>50){ list.add(new ConcreteElement1()); }else{ list.add(new ConcreteElement2()); } } return list; } } public class Client { public static void main(String[] args){ List<Element> list = ObjectStruture.getList(); for(Element e: list){ e.accept(new Visitor()); } } } Advantages of Visitor Mode
Comply with the principle of single responsibility: In any scenario where the visitor mode is applicable, the operations that need to be encapsulated in the visitor in the element class must be operations that have little to do with the element class itself and are volatile. On the one hand, the use of the visitor mode complies with the principle of single responsibility, and on the other hand, because the encapsulated operations are usually volatile, when changes occur, the expansion of the changing part can be achieved without changing the element class itself.
Good scalability: Element classes can extend different operations by accepting different visitors.
Applicable scenarios for visitor mode
If there are some operations in an object that are not related to the object (or weakly related) and in order to avoid these operations contaminating the object, you can use the visitor mode to encapsulate these operations into the visitor.
If there are similar operations in a group of objects, in order to avoid a large number of duplicate code, these duplicate operations can also be encapsulated into the visitor.
However, the visitor mode is not that perfect, and it also has fatal flaws: adding new element classes is more difficult. Through the code of the visitor pattern, we can see that in the visitor class, each element class has its corresponding processing method. That is to say, each element class needs to be added to modify the visitor class (also including the subclass or implementation class of the visitor class), which is quite troublesome to modify. That is to say, when the number of element classes is uncertain, the visitor mode should be used with caution. Therefore, the visitor mode is more suitable for refactoring existing functions. For example, if the basic functions of a project have been determined, the data of element classes have been basically determined and will not change. All that will change is the relevant operations within these elements. At this time, we can use the visitor mode to refactor the original code, so that the original functions can be modified without modifying each element class.
Summarize
As GoF, the author of Design Pattern, describes visitor mode: in most cases, you need to use visitor mode, but once you need it, you really need it. Of course this is only for the real big guys. In reality (at least in the environment I am in), many people are often addicted to design patterns. When using a design pattern, they never seriously consider whether the pattern they are using is suitable for this scenario, but often just want to show their ability to control object-oriented design. If you have this mentality when programming, you often abuse the design pattern. Therefore, when learning design patterns, you must understand the applicability of the patterns. It is necessary to use a pattern because you understand its advantages, not to use a pattern because you understand its disadvantages; rather than to use a pattern because you do not understand its disadvantages, not to use a pattern because you do not understand its advantages.
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.