a schema definition
Visitor Mode: It represents an operation that acts on each element in an object structure, which enables users to define new operations that act on these elements without changing the element classes.
Two-mode example
1 Pattern Analysis
We use the corporate hierarchy to illustrate this pattern.
2 visitor pattern static class diagram
3 Code Examples
3.1 Abstract employee-Staff
package com.demo.structure; import com.demo.visitor.IVisitor; /** * Abstract employee class * * @author * */ public abstract class Staff { // employee ID protected String no; // employee name protected String name; // Position protected String position; // salary protected float salary; // private property length string private int length; // Construction method public Staff(String no, String name, String position, float salary) { this.no = no; this.name = name; this.position = position; this.salary = salary; // Calculate the total length in bytes this.length += (no == null || "".equals(no.trim())) ? 0 : no.getBytes().length; this.length += (name == null || "".equals(name.trim())) ? 0 : name .getBytes().length; this.length += (position == null || "".equals(position.trim())) ? 0 : position.getBytes().length; this.length += String.valueOf(salary).getBytes().length; } // Get basic user information public void printUserBaseInfo() { System.out.println("-|" + this.no + " " + this.name + " " + this.position + " " + this.salary); } // add employee information public abstract void add(Staff staff); // delete employee public abstract Staff remove(String no); // receive the visitor object public abstract void accept(IVisitor visitor); public String getNo() { return no; } public void setNo(String no) { this.no = no; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPosition() { return position; } public void setPosition(String position) { this.position = position; } public float getSalary() { return salary; } public void setSalary(float salary) { this.salary = salary; } }
3.2 Manager-Manager
package com.demo.structure; import java.util.ArrayList; import com.demo.visitor.IVisitor; /** * Managers (people with other employees) * * @author * */ public class Manager extends Staff { // store employee information private final ArrayList<Staff> arrayList = new ArrayList<Staff>(); // Construction method public Manager(String no, String name, String position, float salary) { super(no, name, position, salary); } /** * Add an employee */ @Override public void add(Staff staff) { this.arrayList.add(staff); } /** * Delete employee information */ @Override public Staff remove(String no) { Staff staff = null; if (no != null && !"".equals(no.trim())) { for (int i = 0; i < this.arrayList.size(); i++) { if (this.arrayList.get(i) == null) { continue; } if (no.equals(this.arrayList.get(i).getNo())) { staff = this.arrayList.remove(i); break; } } } return staff; } // receive the visitor object @Override public void accept(IVisitor visitor) { // access itself visitor.visit(this); // Traverse each element object in the list list and receive the visitor object for (int i = 0; i < this.arrayList.size(); i++) { if (this.arrayList.get(i) == null) { continue; } // receive the visitor object this.arrayList.get(i).accept(visitor); } } }
3.3 Ordinary employees - Employees
package com.demo.structure; import com.demo.visitor.IVisitor; /** * Ordinary employees (people who really work) * * @author * */ public class Employees extends Staff { // Construction method public Employees(String no, String name, String position, float salary) { super(no, name, position, salary); } /** * Add employee information */ @Override public void add(Staff staff) { return; } /** * Delete employee information */ @Override public Staff remove(String no) { // directly return null return null; } // receive the visitor object public void accept(IVisitor visitor) { visitor.visit(this); } }
3.4 Visitor interface - IVisitor
package com.demo.visitor; import com.demo.structure.Employees; import com.demo.structure.Manager; /** * Visitor interface * * @author * */ public interface IVisitor { // access manager public void visit(Manager manager); // access ordinary employees public void visit(Employees employees); }
3.5 Employee Basic Information Visitor - PrintBaseInfoVistor
package com.demo.visitor; import com.demo.structure.Employees; import com.demo.structure.Manager; /** * Print basic information for visitors * * @author * */ public class PrintBaseInfoVisitor implements IVisitor { /** * access manager object */ public void visit(Manager manager) { System.out.print("- manager: "); manager.printUserBaseInfo(); } /** * Access common employee objects */ public void visit(Employees employees) { System.out.print("- General staff: "); employees.printUserBaseInfo(); } }
3.6 Create a visitor interface for employee salary statistics - ISalaryVistor
package com.demo.visitor; /** * Calculate salary for visitors * * @author * */ public interface ISalaryVisitor extends IVisitor { // Statistics manager salary public void printManagerTotalSalary(); // Statistics of general employee salary public void printEmployeesTotalSalary(); // Calculate the salary of all employees public void printTotalSalary(); }
3.7 Statistical Employee Salary Visitor Implementation of a SalaryVistor
package com.demo.visitor; import com.demo.structure.Employees; import com.demo.structure.Manager; /** * Calculate salary visitor specific implementation * * @author * */ public class SalaryVisitor implements ISalaryVisitor { // total manager salary private float managerSalary; // The total salary of ordinary employees private float employeesSalary; public SalaryVisitor() { managerSalary = 0; employeesSalary = 0; } // access manager public void visit(Manager manager) { managerSalary += manager.getSalary(); } // access ordinary employees public void visit(Employees employees) { employeesSalary += employees.getSalary(); } // Statistics of general employee salary public void printEmployeesTotalSalary() { System.out.println("General employee salary sum: " + employeesSalary); } // Statistics manager salary public void printManagerTotalSalary() { System.out.println("Manager Salary Sum: " + managerSalary); } // Calculate the salary of all employees public void printTotalSalary() { System.out.println("Employee Salary Sum: " + (managerSalary + employeesSalary)); } }
3.8 Client Test One Client
package com.demo; import com.demo.structure.Employees; import com.demo.structure.Manager; import com.demo.structure.Staff; import com.demo.visitor.PrintBaseInfoVisitor; import com.demo.visitor.SalaryVisitor; /** * Main application * * @author * */ public class Client { /** * @param args */ public static void main(String[] args) { // Company CEO Staff boss = new Manager("1", "大老板", "CEO", 100000); /** * There are several department managers under the CEO */ // Finance Manager Staff financeManager = new Manager("11", "Mr. Zhang", "Finance Manager", 60000); // HR manager Staff personnelManager = new Manager("12", "Mr. Wang", "Personnel Manager", 60000); // technical manager Staff technicalManager = new Manager("13", "Mr. Chen", "Technical Manager", 60000); /** * The technical department also has assistants and several supervisors */ // technical department assistant Staff deptAssistant = new Manager("1301", "Assistant Wang", "Dept Assistant", 20000); // Head of technical department 1 Staff deptManager1 = new Manager("1302", "Supervisor 1", "Technical Supervisor", 30000); /** * There are also software engineers under the technical director deptManager1 (the one who does the final work) */ Staff softwareEngineer1 = new Employees("1302001", "Zhang San", "Software Engineer", 5000); Staff softwareEngineer2 = new Employees("1302002", "Li Si", "Software Engineer", 5500); Staff softwareEngineer3 = new Employees("1302003", "Wang Wu", "Software Engineer", 4500); // Add employee information for technical supervisor 1 deptManager1.add(softwareEngineer1); deptManager1.add(softwareEngineer2); deptManager1.add(softwareEngineer3); // Head of technical department 2 Staff deptManager2 = new Manager("1303", "Supervisor 2", "Technical Supervisor", 30000); // Added for Technical Manager: Department Assistant, Technical Supervisor 1 and Technical Supervisor 2 technicalManager.add(deptAssistant); technicalManager.add(deptManager1); technicalManager.add(deptManager2); // Marketing Manager Staff marketingManager = new Manager("14", "Mr. Wu", "Marketing Manager", 60000); // Added for CEO: Finance Manager, HR Manager, Technical Manager and Marketing Manager boss.add(financeManager); boss.add(personnelManager); boss.add(technicalManager); boss.add(marketingManager); // print CEO info // boss.printUserBaseInfo(); // Print the employee information of the CEO boss.accept(new PrintBaseInfoVisitor()); /** * Statistics on employee salary */ // Create a statistical employee salary visitor SalaryVisitor visitor = new SalaryVisitor(); // Let the big boss accept the visitor boss.accept(visitor); // manager salary statistics visitor.printManagerTotalSalary(); // General employee salary statistics visitor.printEmployeesTotalSalary(); // All employee salary statistics visitor.printTotalSalary (); } }
4 Running results
- Manager: -|1 Big Boss CEO 100000.0
- Manager: -|11 Zhang, Manager of General Finance Department 60000.0
- Manager: -|12 Mr. Wang, Manager of Personnel Department 60000.0
- Manager: -|13 General Manager Chen Technology Department 60000.0
- Manager: -|1301 Assistant Wang Department Assistant 20000.0
- Manager: -|1302 Supervisor 1 Technical Supervisor 30000.0
- General staff:-|1302001 Zhang San Software Engineer 5000.0
- General staff:-|1302002 Li Si software engineer 5500.0
- General staff:-|1302003 Wang Wu Software Engineer 4500.0
- Manager: -|1303 Supervisor 2 Technical Supervisor 30000.0
- Manager: -|14 Wu, Manager of Marketing Department 60000.0
Total salary of managers: 420000.0
General employee salary sum: 15000.0
Total employee salary: 435000.0
Three principles of pattern design
1 "Open-close" principle
2 Single Responsibility Principle
Four use cases
1 If there are many objects of different types in an object structure, they have different interfaces, and you want to implement some operations that depend on concrete classes on these different objects.
2 Need to perform many different and unrelated operations on objects in an object structure, and want to avoid having those operations associated with the classes of those objects. The visitor pattern makes it possible to group related operations together and define them in a single class.
3 When the object structure is shared by many applications, use the visitor pattern to let each application contain only the operations it needs to use.
4 The class that defines the structure of an object rarely changes, but it is often necessary to define new operations in this structure.
Five visitor pattern static class diagram