Visitor Design Pattern in Java
Learn Visitor Design Pattern in Java with double dispatch, object structure traversal, reporting systems, tax calculation engines, AST processing, enterprise use cases, UML diagrams, and interview questions.
What You Will Learn
- What is Visitor Pattern?
- Why Visitor Pattern is Needed
- Double Dispatch Explained
- Object Structure Traversal
- Reporting Engine Example
- Tax Calculation Example
- Java Implementation
- Enterprise Use Cases
- Benefits and Limitations
- Interview Questions
Introduction
Imagine an e-commerce system contains:
Product
Book
Laptop
Mobile
Furniture
Now business asks for:
Tax Calculation
Discount Calculation
Report Generation
Export To PDF
Export To Excel
Without Visitor Pattern:
class Book {
calculateTax();
generateReport();
exportPdf();
exportExcel();
}
Every time a new operation is added:
Modify All Classes
This violates:
Open Closed Principle
Visitor Pattern solves this problem.
What is Visitor Pattern?
Visitor is a Behavioral Design Pattern that lets you add new operations to existing object structures without modifying those structures.
Simple View:
Object Structure
↓
Visitor
↓
Operation
Purpose of Visitor Pattern
Primary Goal:
Add New Operations
Without Modifying Existing Classes
Real World Analogy
Think about a hospital.
Patients:
Adult Patient
Child Patient
Senior Patient
Visitors:
Doctor
Nurse
Insurance Auditor
Each visitor performs different operations on the same patient.
Problem Without Visitor
flowchart LR
A[Book]
B[Laptop]
C[Mobile]
A --> D[Tax Logic]
B --> D
C --> D
A --> E[Report Logic]
B --> E
C --> E
Every class contains every operation.
Hard to maintain.
Solution With Visitor
flowchart LR
A[Book]
B[Laptop]
C[Mobile]
D[Tax Visitor]
E[Report Visitor]
D --> A
D --> B
D --> C
E --> A
E --> B
E --> C
Operations move into visitors.
Visitor Architecture
flowchart LR
A[Element]
B[Visitor]
A --> B
Key Components
Visitor
Defines operations.
Concrete Visitor
Implements operations.
Element
Accepts visitors.
Object Structure
Collection of elements.
UML Diagram
classDiagram
class Visitor {
+visit(Book)
+visit(Laptop)
}
class TaxVisitor
class ReportVisitor
class Product {
+accept()
}
class Book
class Laptop
Visitor <|.. TaxVisitor
Visitor <|.. ReportVisitor
Product <|-- Book
Product <|-- Laptop
Example Scenario
Products:
Book
Laptop
Operations:
Calculate Tax
Generate Report
Step 1: Visitor Interface
public interface Visitor {
void visit(Book book);
void visit(Laptop laptop);
}
Step 2: Product Interface
public interface Product {
void accept(
Visitor visitor);
}
Step 3: Book Class
public class Book
implements Product {
private double price;
public Book(
double price) {
this.price = price;
}
public double getPrice() {
return price;
}
@Override
public void accept(
Visitor visitor) {
visitor.visit(this);
}
}
Step 4: Laptop Class
public class Laptop
implements Product {
private double price;
public Laptop(
double price) {
this.price = price;
}
public double getPrice() {
return price;
}
@Override
public void accept(
Visitor visitor) {
visitor.visit(this);
}
}
Step 5: Tax Visitor
public class TaxVisitor
implements Visitor {
@Override
public void visit(
Book book) {
System.out.println(
"Book Tax: "
+ book.getPrice() * 0.05);
}
@Override
public void visit(
Laptop laptop) {
System.out.println(
"Laptop Tax: "
+ laptop.getPrice() * 0.18);
}
}
Step 6: Report Visitor
public class ReportVisitor
implements Visitor {
@Override
public void visit(
Book book) {
System.out.println(
"Book Report Generated");
}
@Override
public void visit(
Laptop laptop) {
System.out.println(
"Laptop Report Generated");
}
}
Step 7: Client
public class VisitorDemo {
public static void main(
String[] args) {
Product book =
new Book(100);
Product laptop =
new Laptop(1000);
Visitor taxVisitor =
new TaxVisitor();
Visitor reportVisitor =
new ReportVisitor();
book.accept(taxVisitor);
laptop.accept(taxVisitor);
book.accept(reportVisitor);
laptop.accept(reportVisitor);
}
}
Output
Book Tax: 5.0
Laptop Tax: 180.0
Book Report Generated
Laptop Report Generated
Execution Flow
flowchart LR
A[Product]
B[Accept Visitor]
C[Visitor Operation]
D[Result]
A --> B
B --> C
C --> D
Double Dispatch Explained
Visitor Pattern uses:
Double Dispatch
Normal Java:
object.method();
Single dispatch.
Visitor:
visitor.visit(book);
Runtime determines:
Visitor Type
+
Element Type
This is called:
Double Dispatch
Double Dispatch Flow
flowchart LR
A[Visitor]
B[Book]
C[Visit Method]
A --> C
B --> C
Tax Calculation Example
Products:
Book
Laptop
Mobile
Different tax rates.
Tax Engine Architecture
flowchart LR
A[Product]
B[Tax Visitor]
C[Tax Result]
A --> B
B --> C
Reporting System Example
Generate:
PDF Report
Excel Report
CSV Report
without modifying Product classes.
Reporting Flow
flowchart LR
A[Product]
B[Report Visitor]
C[PDF]
D[Excel]
E[CSV]
B --> C
B --> D
B --> E
A --> B
Banking Example
Account Types:
Savings
Current
Loan
Visitors:
Interest Calculator
Risk Analyzer
Audit Report
Banking Workflow
flowchart LR
A[Savings]
B[Current]
C[Loan]
D[Interest Visitor]
D --> A
D --> B
D --> C
Insurance Example
Policies:
Health
Vehicle
Life
Visitors:
Premium Calculator
Claim Auditor
Risk Analyzer
Insurance Architecture
flowchart LR
A[Policy]
B[Premium Visitor]
C[Risk Visitor]
A --> B
A --> C
Compiler Example
Visitor is heavily used in:
AST Processing
Code Analysis
Compilers
Parsers
AST Traversal
flowchart LR
A[AST Node]
B[Visitor]
C[Code Generation]
A --> B
B --> C
Enterprise Examples
Banking
Interest Calculation
Risk Assessment
Audit Reporting
Insurance
Premium Calculation
Fraud Analysis
Claim Reporting
Retail
Tax Calculation
Invoice Generation
Discount Reports
Compiler Systems
AST Traversal
Optimization
Code Generation
Spring Framework Examples
Common Visitor-like implementations:
BeanPostProcessor
HandlerMethodArgumentResolver
Jackson Object Traversal
AST Visitors
Benefits
✅ Open Closed Principle
✅ Easy To Add New Operations
✅ Centralized Logic
✅ Cleaner Domain Objects
✅ Excellent For Reporting Systems
✅ Supports Complex Object Structures
Limitations
❌ Adding New Element Types Is Hard
❌ More Classes
❌ Increased Complexity
❌ Tight Coupling Between Visitor And Elements
When To Use
Use Visitor Pattern when:
- Object structure is stable
- New operations are added frequently
- Reporting systems exist
- Tax calculations vary
- AST traversal is needed
When Not To Use
Avoid when:
- Element types change frequently
- Object structure is unstable
Visitor vs Strategy
| Feature | Visitor | Strategy |
|---|---|---|
| Purpose | Add Operations | Change Algorithm |
| Focus | Object Structure | Behavior |
| Uses Double Dispatch | Yes | No |
Visitor vs Decorator
| Feature | Visitor | Decorator |
|---|---|---|
| Goal | Add Operations | Add Behavior |
| Modifies Object | No | Yes |
| Focus | External Processing | Runtime Enhancement |
Real Enterprise Architecture
flowchart LR
A[Domain Objects]
B[Visitor Engine]
C[Reports]
D[Tax Calculation]
E[Analytics]
A --> B
B --> C
B --> D
B --> E
Interview Questions
What is Visitor Pattern?
A behavioral pattern that allows adding new operations without modifying existing object structures.
Main Components?
Visitor
Concrete Visitor
Element
Object Structure
What is Double Dispatch?
Method execution based on both visitor type and element type.
Real World Example?
Tax Calculation Engine.
Enterprise Example?
Reporting Systems and AST Processing.
Main Benefit?
Adding new operations without changing domain classes.
Key Takeaways
- Visitor is a Behavioral Design Pattern.
- Separates operations from object structures.
- Uses Double Dispatch.
- Excellent for Reporting, Tax Calculation, and AST Processing.
- Follows Open Closed Principle.
- Common in Banking, Insurance, Retail, and Compiler Systems.
- Best when object structure is stable but operations change frequently.
Design Patterns Series Completed
Creational Patterns
- Singleton
- Factory Method
- Abstract Factory
- Builder
- Prototype
Structural Patterns
- Adapter
- Bridge
- Composite
- Decorator
- Facade
- Flyweight
- Proxy
Behavioral Patterns
- Chain Of Responsibility
- Command
- Interpreter
- Iterator
- Mediator
- Memento
- Observer
- State
- Strategy
- Template Method
- Visitor