Java design pattern (3) Visitor pattern and Application in Multi-Dispatch scenarios
The basic concept of Visitor encapsulates operations that act on each element in the data structure. Different operations can be implemented with the help of the new visitor, reducingCouplingVisitors canData StructureAndData OperationsDecoupling makes it unnecessary to modify the data structure or modify the original operation for the added operations on the data structure. When executing the operation, you can define the new Visitor (Easy expansion in adding operations) Role DivisionVisitor: Abstract visitor. Declare the visitor in the overloaded visit function.Accessible objects.Concrete Visitor: Allows a visitor to operate on a specific element.Element: An abstract element that declares the type of the visitor who has the permission to access this type of element (usually an abstract type) and provides the overloaded accept function.Grant Permissions Concrete Element: The accept method is basically templated visitor. visit (this)Object Structure: Contains a set of different types, interfaces, or elements. For example, the implementation of Visitor is a simple example to show a basic and simple Visitor.
In the spring recruitment season, we will give an example of resume screening. All resumes are for undergraduates, junior students, master students, and higher vocational students... Take the first two for simplicity. The resume of a job seeker is implemented as an Element as follows:
Abstract class Student {// provides the function private String name; private String university; private String rating for basic operations on data domains; // obtain the permission of the specified visitor to operate on the object. public abstract void accept (Visitor visitor); public String getName () {return name;} public void setName (String name) {this. name = name;} public String getUniversity () {return university;} public void setUniversity (String university) {this. university = university;} public String getRating () {return rating;} public void setRating (String rating) {this. rating = rating;} class Bachelor extends Student {@ Override public void accept (Visitor visitor) {visitor. visit (this) ;}} class College extends Student {@ Override public void accept (Visitor visitor) {visitor. visit (this );}}
Because we only define two types of students, the interface provides two types of Element access.
interface Visitor{ public void visit ( Bachelor bachelor ); public void visit ( College college );}
First, we need a ShowVisitor to check what your resume looks like:
Class ShowVisitor implements Visitor {@ Override public void visit (Bachelor bachelor) {System. out. println ("A bachelor \ n"); // TODO may have some special operations. we omit this for simplicity. printMessage (bachelor);} @ Override public void visit (College college) {System. out. println ("a college student! \ N "); // TODO is the same as this. printMessage (college);} public void printMessage (Student student) {System. out. println ("Name:" + student. getName () + "\ n" + "University:" + student. getUniversity () + "\ n" + "Rating:" + student. getRating () + "\ n ");}}
To perform a test, we first need to construct a data set, that is, the ObjectStructure corresponding to the role. For simplicity, we directly use ArrayList.
public class VisitorEg { public static void main ( String [] args ){ ArrayList
list = new ArrayList
(); Bachelor bachelor = new Bachelor(); bachelor.setName("llin"); bachelor.setRating("100"); bachelor.setUniversity("Tianjin University"); College college = new College(); college.setUniversity("Tianjin college"); college.setRating("1"); college.setName("dalinge"); list.add ( bachelor ); list.add ( college ); Visitor visitor = new ShowVisitor(); for ( Student student: list ){ student.accept( visitor ); } }}
It seems that the visitor mode has no advantages !!! It's a lot of trouble, but because you have separated the data structure from the operations on the data (Decoupling), So when I want to add a new operation, I don't need to modify the original class. I just need to implement a new visitor.
So, let's go back to this example. How many undergraduates are enrolled? (if there are enough students, they may just be lazy and only interview undergraduates, therefore, we need a statistical Visitor:
class SumVisitor implements Visitor{ private int totalBachelor; SumVisitor(){ super(); totalBachelor = 0; } @Override public void visit(Bachelor bachelor) { totalBachelor++; } @Override public void visit(College college) { } public int getTotal_bachelor() { return totalBachelor; }}public class VisitorEg { public static void main ( String [] args ){ ArrayList
list = new ArrayList
(); Bachelor bachelor = new Bachelor(); bachelor.setName("llin"); bachelor.setRating("100"); bachelor.setUniversity("Tianjin University"); College college = new College(); college.setUniversity("Tianjin college"); college.setRating("1"); college.setName("dalinge"); list.add ( bachelor ); list.add ( college ); Visitor visitor = new ShowVisitor(); Visitor visitor1 = new SumVisitor(); for ( Student student: list ){ student.accept( visitor ); student.accept( visitor1); } System.out.println( "The total sum of bachelors : "+ ((SumVisitor)visitor1).getTotal_bachelor() ); }}
I met the requirements but did not modify a line of code!
In the Visitor application scenario, you must have the following questions: What is the difference between visitor and iterator: visitor can access
Different(You only need to define the corresponding accept in the Element), but Iterator can only access the same object, at least there must be
SameThe iterator of is
Independent of specific implementationsAnd visitor is
Depends on the specific implementationBecause Visitor takes corresponding operations based on the specific objects accessed, and iterator is only generalized based on the same interface at most. The operations and data of the Data Structure accessed by iterator are not separated, so the extended functions need to be modified,
Violation of the open/closed PrincipleAnd
Single Responsibility Principle. However, because the visitor depends on the specific implementation rather than the abstraction
Violation of the dependency inversion principleThe Application Scenario determined by the advantages and disadvantages conforms to the single responsibility principle and has good scalability in terms of functions. However, the dependency implementation violates the specific implementation, which makes it difficult to modify classes. With excellent scalability, you only need to implement new Visitor to meet new access requirements. The separation of data and operations prevents adding new operations from polluting the original data structure. To sum up
Visitors areCentralized normalization ModeIt is particularly suitable for large-scale reconstruction projects. The requirements at this stage have been very clear, and the functions of the original system have been clearly defined. Through the visitor mode, you can easily sort out some functions, achieve the ultimate goalCentralized functions
Double dispatch first introduces the following single dispatch
Single Assignment: An operation depends on the name of the requester and the received parameters.Static bindingAndDynamic binding, Respectively throughHeavy LoadAndOverwrite.
Double dispatch: Double dispatch means that the operation to be executed depends onRequest typeAndRecipient type. CorrespondsVisitor Mode.
Javac adopts the Visitor mode (syntax and semantic analysis phase) when constructing, optimizing, and parsing the syntax tree)