You have a stable set of element types (e.g., Book, Electronics, Clothing) but you want to add new operations (e.g., calculateTax(), generateReport(), exportToJson()) without modifying each element class. Visitor lets you define a new operation without changing the elements.
// ─── EXAMPLE 1 ──────────────────────────────────────────────────────────────
// WHAT WE ARE IMPLEMENTING:
// An office suite document exporter formatting texts and diagrams to PDF or
// plain text formats cleanly.
//
// WHERE THE VISITOR FITS IN:
// DocumentElement is the Element interface accepting visitors. TextElement
// represents a Concrete Element. DocumentVisitor acts as the Visitor
// declaring visit().
// ────────────────────────────────────────────────────────────────────────────
import java.util.ArrayList;
import java.util.List;
// --- Visitor interface (one visit method per element type) ---
interface ShoppingCartVisitor {
double visit(Book book);
double visit(Electronics electronics);
double visit(Clothing clothing);
}
// --- Element interface ---
interface ItemElement {
double accept(ShoppingCartVisitor visitor);
}
// --- Concrete elements (stable types) ---
class Book implements ItemElement {
private final double price;
private final String isbn;
public Book(double price, String isbn) { this.price = price; this.isbn = isbn; }
public double getPrice() { return price; }
public String getIsbn() { return isbn; }
public double accept(ShoppingCartVisitor visitor) { return visitor.visit(this); }
}
class Electronics implements ItemElement {
private final double price;
private final String brand;
public Electronics(double price, String brand) { this.price = price; this.brand = brand; }
public double getPrice() { return price; }
public String getBrand() { return brand; }
public double accept(ShoppingCartVisitor visitor) { return visitor.visit(this); }
}
class Clothing implements ItemElement {
private final double price;
private final String size;
public Clothing(double price, String size) { this.price = price; this.size = size; }
public double getPrice() { return price; }
public String getSize() { return size; }
public double accept(ShoppingCartVisitor visitor) { return visitor.visit(this); }
}
// --- Concrete visitor (one operation) ---
class TaxCalculator implements ShoppingCartVisitor {
public double visit(Book book) {
// Books: 5% tax
double tax = book.getPrice() * 0.05;
System.out.println(" [Tax] Book ISBN=" + book.getIsbn() + " tax=" + tax);
return tax;
}
public double visit(Electronics electronics) {
// Electronics: 18% tax (GST)
double tax = electronics.getPrice() * 0.18;
System.out.println(" [Tax] Electronics brand=" + electronics.getBrand() + " tax=" + tax);
return tax;
}
public double visit(Clothing clothing) {
// Clothing: 12% tax
double tax = clothing.getPrice() * 0.12;
System.out.println(" [Tax] Clothing size=" + clothing.getSize() + " tax=" + tax);
return tax;
}
}
// --- Another visitor (new operation, no element changes needed) ---
class DiscountCalculator implements ShoppingCartVisitor {
public double visit(Book book) {
double discount = 0;
if (book.getPrice() > 500) discount = book.getPrice() * 0.10;
System.out.println(" [Discount] Book discount=" + discount);
return discount;
}
public double visit(Electronics electronics) {
double discount = electronics.getPrice() * 0.05;
System.out.println(" [Discount] Electronics discount=" + discount);
return discount;
}
public double visit(Clothing clothing) {
double discount = 0;
if (clothing.getSize().equals("S") || clothing.getSize().equals("XS")) discount = clothing.getPrice() * 0.15;
System.out.println(" [Discount] Clothing discount=" + discount);
return discount;
}
}
public class Main {
public static void main(String[] args) {
List<ItemElement> items = new ArrayList<>();
items.add(new Book(600, "ISBN-1234"));
items.add(new Electronics(15000, "Samsung"));
items.add(new Clothing(800, "M"));
ShoppingCartVisitor taxCalc = new TaxCalculator();
ShoppingCartVisitor discountCalc = new DiscountCalculator();
double totalTax = 0, totalDiscount = 0;
for (ItemElement item : items) {
totalTax += item.accept(taxCalc);
totalDiscount += item.accept(discountCalc);
}
System.out.println("\nTotal tax: $" + totalTax);
System.out.println("Total discount: $" + totalDiscount);
}
}