In this article, we will do an in-depth exploration of Visitor Design Pattern in Java. So, let’s get started.
What is Visitor Design Pattern in Java ?
The Visitor Design Pattern in Java is a powerful and flexible design pattern in the realm of object-oriented programming. It allows for the separation of algorithms or operations from the objects they operate on, enabling the addition of new operations without modifying the existing object structure.
Benefits: Visitor Design Pattern in Java
The Visitor Design Pattern offers several benefits when used in Java applications:
- Separation of Concerns: The pattern separates the algorithm for performing operations on objects from the objects themselves.
- Extensibility: The Visitor pattern allows for easy addition of new operations without modifying the existing classes. New visitor implementations can be added independently, making the system more extensible and adaptable to future changes.
- Open/Closed Principle: The pattern adheres to the Open/Closed Principle, which states that software entities should be open for extension but closed for modification. With the Visitor pattern, new behaviors can be added by implementing new visitor classes, without modifying the existing code.
- Maintainability: By encapsulating related operations within visitor classes, the code becomes more organized and maintainable. Changes to the behavior or implementation of a specific operation can be isolated within the corresponding visitor class.
- Reusability: The Visitor pattern promotes code reuse by allowing multiple visitors to work with the same set of objects. Different visitors can provide different operations on the objects, enabling modular and reusable code.
- Pattern Matching: The Visitor pattern provides a powerful mechanism for pattern matching and dispatching based on the type and structure of objects. This can be particularly useful in scenarios where complex object hierarchies and operations need to be handled.
Real World Use Cases of the Visitor Design Pattern in Java
Here are some real-world use cases of the Visitor Design Pattern in Java:
- Document Processing: The Visitor pattern can be used to process various elements in a document structure, such as paragraphs, images, and tables. Each element can accept a visitor, which performs specific operations based on the type of element.
- Compiler Design: In compiler design, the Visitor pattern is often used for traversing the abstract syntax tree (AST) and performing operations on different types of nodes. Each node type can accept a visitor, which performs actions like type checking, code generation, or optimization.
- GUI Components: The Visitor pattern can be used in graphical user interface (GUI) frameworks to process different types of UI components, such as buttons, checkboxes, and text fields. The visitor can perform operations like rendering, event handling, or data binding.
- Database Operations: When working with databases, the Visitor pattern can be applied to process different types of database objects, such as tables, views, or indexes. The visitor can perform actions like querying, updating, or deleting data based on the object type.
- XML/JSON Parsing: Visitor pattern can be utilized in parsing XML or JSON documents. Each element or node in the document can accept a visitor, which extracts or processes data from that element.
Components: Visitor Design Pattern in Java
Example: Visitor Design Pattern in Java
In the below example, we will move the logic for calculating billing and missed billed hours for employees to our visitor classes.
Class Diagram
Java Code
// Employee Interface
package com.design.visitor;
public interface Employee {
public void accept(EmployeeVisitor employeeVisitor);
}
// PermanentEmployee class
package com.design.visitor;
public class PermanentEmployee implements Employee {
private double averageHours;
private String name;
public double getAverageHours() {
return averageHours;
}
public void setAverageHours(double averageHours) {
this.averageHours = averageHours;
}
public String getName() {
return name;
}
public PermanentEmployee(double averageHours, String name) {
this.averageHours = averageHours;
this.name = name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void accept(EmployeeVisitor employeeVisitor) {
employeeVisitor.visit(this);
}
}
// ContractualEmployee Class
package com.design.visitor;
public class ContractualEmployee implements Employee {
private double averageHours;
private String name;
public double getAverageHours() {
return averageHours;
}
public void setAverageHours(double averageHours) {
this.averageHours = averageHours;
}
public String getName() {
return name;
}
public ContractualEmployee(double averageHours, String name) {
this.averageHours = averageHours;
this.name = name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void accept(EmployeeVisitor employeeVisitor) {
employeeVisitor.visit(this);
}
}
// EmployeeVisitor Interface
package com.design.visitor;
public interface EmployeeVisitor {
public void visit(PermanentEmployee permanentEmployee);
public void visit(ContractualEmployee permanentEmployee);
}
// BillingVisitor Class
package com.design.visitor;
public class BillingVisitor implements EmployeeVisitor {
public static double permanentEmployee = 10;
public static double contractEmployee = 9;
@Override
public void visit(PermanentEmployee permanentEmployee) {
System.out.println("Total Billing for last month for " + permanentEmployee.getName() + ":" + permanentEmployee.getAverageHours() *
BillingVisitor.permanentEmployee * 22 + "$");
}
@Override
public void visit(ContractualEmployee contractualEmployee) {
System.out.println("Total Billing for last month for " + contractualEmployee.getName() + ":" + contractualEmployee.getAverageHours() *
BillingVisitor.contractEmployee * 22 + "$");
}
}
// MissingBilledHoursVisitor Class
package com.design.visitor;
public class MissingBilledHoursVisitor implements EmployeeVisitor {
public static double permanentEmployee = 9.5;
public static double contractEmployee = 9.0;
@Override
public void visit(PermanentEmployee permanentEmployee) {
System.out.println("Missed Billing Hours for last month for " + permanentEmployee.getName() + ":" +
(MissingBilledHoursVisitor.permanentEmployee - permanentEmployee.getAverageHours()) * 22 + " Hrs");
}
@Override
public void visit(ContractualEmployee contractualEmployee) {
System.out.println("Missed Billing Hours for last month for " + contractualEmployee.getName() + ":" + (MissingBilledHoursVisitor.contractEmployee -
contractualEmployee.getAverageHours()) * 22 + " Hrs");
}
}
// VisitorDemo Class
package com.design.visitor;
public class VisitorDemo {
public static void main(String[] args) {
EmployeeVisitor billingVisitor = new BillingVisitor();
EmployeeVisitor missingBilledHoursVisitor = new MissingBilledHoursVisitor();
Employee permanentEmployee = new PermanentEmployee(9, "Gyan");
Employee contractualEmployee = new ContractualEmployee(7, "Rochit");
permanentEmployee.accept(billingVisitor);
contractualEmployee.accept(billingVisitor);
permanentEmployee.accept(missingBilledHoursVisitor);
contractualEmployee.accept(missingBilledHoursVisitor);
}
}
// Output
Total Billing
for last month
for Gyan: 1980.0 $
Total Billing
for last month
for Rochit: 1386.0 $
Missed Billing Hours
for last month
for Gyan: 11.0 Hrs
Missed Billing Hours
for last month
for Rochit: 44.0 Hrs
Conclusion :Visitor Design Pattern in Java
Visitor Design Pattern in Java allows for the separation of operations from objects, enabling easy addition of new behaviors. By exploring its benefits, real-world applications, and practical examples, you can unlock the potential of this design pattern for enhancing modularity, extensibility, and maintainability in your Java projects.
Must Read Design Pattern Articles:
- Professional Tips: Top 10 Design Principles in Java 2023
- SOLID principles in Java: A Comprehensive Guide in 2023
- Design Patterns in Java: For Efficient Development 2023
Recommended Books:
- “Design Patterns: Elements of Reusable Object-Oriented Software” by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides (also known as the Gang of Four book)
- “Head First Design Patterns” by Eric Freeman, Elisabeth Robson, Bert Bates, and Kathy Sierra