The Visitor Design Pattern
Haim Michael
June 3rd
, 2025
All logos, trade marks and brand names used in this presentation belong
to the respective owners.
The new Java Way
www.lifemichael.com
© 2008 Haim Michael 20150805
Introduction
 The use of Record classes in Java can significantly improve
the implementation of the Visitor design pattern. Especially
when combined with sealed classes and pattern matching.
© 2008 Haim Michael 20150805
Table Of Content
 The Programming Problem
The programming problem the Visitor classic design pattern solves.
 The Traditional Implementation
The traditional implementation of the Visitor classic design pattern in Java.
 The Modern Implementation
The modern implementation of the Visitor classic design pattern in Java with Records,
Sealed Classes, and Pattern Matching.
 The Benefits of Using Records
The benefits of using Records, Sealed Classes, and Pattern Matching when implementing
the Visitor classic design pattern.
© 2008 Haim Michael 20150805
Prerequisites
 Basic Understanding of Record Classes, Sealed Classes, and
Pattern Matching in Java.
© 2008 Haim Michael 20150805
The Programming Problem (1 out of 4)
 In many object-oriented systems, we have a class hierarchy
(e.g., expression tree, shape hierarchy) that we want to
traverse or operate on in different ways - such as evaluating,
rendering, or pretty-printing.
 If we add new operations directly to these classes, we might
unintentionally clutter the new code with unrelated logic. In
addition, we will need to modify existing classes whenever
adding new operators.
© 2008 Haim Michael 20150805
The Programming Problem (2 out of 4)
 The Visitor classic design pattern aims at solving the following
programming problem:
How can we define new operations on a set of related object
types (e.g., binary tree nodes, shapes, expressions) without
modifying their source code and without duplicating logic
across types?
© 2008 Haim Michael 20150805
The Programming Problem (3 out of 4)
 The intent of the Visitor classic design pattern according to
the Gang of Four:
Represent an operation to be performed on the elements of
an object structure. Visitor lets you define a new operation
without changing the classes of the elements on which it
operates.
© 2008 Haim Michael 20150805
The Programming Problem (4 out of 4)
 The Visitor pattern decouples the operations from the object
structure, allowing us to define new operations without
changing the element classes.
© 2008 Haim Michael 20150805
The Traditional Implementation (1 out of 4)
 Implementing the Visitor classic design pattern without using
Record Classes, Sealed Classes, and Pattern Matching will
require having an object that plays the role of a visitor. That
object will pays a visit to each one of the objects by calling a
method (the accept method) on each one of these objects.
Inside the accept method, the visit method will be invoked
on the Visitor object. The reference of the visited object will
be passed over to it.
© 2008 Haim Michael 20150805
The Traditional Implementation (2 out of 4)
public interface Expression {
<T> T accept(Visitor<T> visitor);
}
public interface Visitor<T> {
T visit(Number num);
T visit(Total total);
T visit(Multiplication mul);
T visit(Difference diff);
}
public class Number implements Expression {
public final int value;
public Number(int value) { this.value = value; }
public <T> T accept(Visitor<T> visitor) {
return visitor.visit(this);
}
}
© 2008 Haim Michael 20150805
The Traditional Implementation (3 out of 4)
public interface Expression {
<T> T accept(Visitor<T> visitor);
}
public class Multiplication implements Expression {
public final Expression left, right;
public Multiplication(Expression left, Expression right) {
this.left = left;
this.right = right;
}
public <T> T accept(Visitor<T> visitor) {
return visitor.visit(this);
}
}
public class Total implements Expression { ... }
public class Subtraction implements Expression { ... }
© 2008 Haim Michael 20150805
The Traditional Implementation (4 out of 4)
public class SimpleVisitor implements Visitor<Integer> {
public Integer visit(Number num) {
return num.value;
}
public Integer visit(Total ob) {
return ob.left.accept(this) + ob.right.accept(this);
}
public Integer visit(Multiplication ob) {
return ob.left.accept(this) * ob.right.accept(this);
}
public Integer visit(Difference ob) {
return ob.left.accept(this) - ob.right.accept(this);
}
}
© 2008 Haim Michael 20150805
The Modern Implementation (1 out of 4)
 Implementing the Visitor classic design pattern when using
Record Classes, Sealed Classes and Pattern Matching might
become simpler.
 We will define a method that will take an Expression object
that using pattern matching will evaluate it according to its
type.
© 2008 Haim Michael 20150805
The Modern Implementation (2 out of 4)
public sealed interface Expression
permits Number, Total, Difference, Multiplication {}
public record Number(int value)
implements Expression {}
public record Total(Expression left, Expression right)
implements Expression {}
public record Difference (Expression left, Expression right)
implements Expression {}
public record Multiplication (Expression left, Expression right)
implements Expression {}
© 2008 Haim Michael 20150805
The Modern Implementation (3 out of 4)
public class Evaluator {
public int evaluate(Expression expression) {
return switch (expression) {
case Number(int value) -> value;
case Total(Expression left, Expression right) ->
evaluate(left) + evaluate(right);
case Multiplication(Expression left, Expression right) ->
evaluate(left) * evaluate(right);
case Difference(Expression left, Expression right) ->
evaluate(left) - evaluate(right);
};
}
}
© 2008 Haim Michael 20150805
The Modern Implementation (4 out of 4)
public class Program {
public static void main(String[] args) {
Expression expression = new Multiplication(
new Total(new Number(3),new Number(2)),
new Total(new Number(6),new Number(4)));
System.out.println(new Evaluator().evaluate(expression));
}
}
© 2008 Haim Michael 20150805
The Benefits
 The code becomes cleaner and there is no need in the
additional accept() method.
© 2009 Haim Michael All Rights Reserved 18
Questions & Answers
Thanks for Your Time!
Haim Michael
haim.michael@lifemichael.com
+972+3+3726013 ext:700
+972+54+6655837 (whatsapp)

The Visitor Classic Design Pattern [Free Meetup]

  • 1.
    The Visitor DesignPattern Haim Michael June 3rd , 2025 All logos, trade marks and brand names used in this presentation belong to the respective owners. The new Java Way www.lifemichael.com
  • 2.
    © 2008 HaimMichael 20150805 Introduction  The use of Record classes in Java can significantly improve the implementation of the Visitor design pattern. Especially when combined with sealed classes and pattern matching.
  • 3.
    © 2008 HaimMichael 20150805 Table Of Content  The Programming Problem The programming problem the Visitor classic design pattern solves.  The Traditional Implementation The traditional implementation of the Visitor classic design pattern in Java.  The Modern Implementation The modern implementation of the Visitor classic design pattern in Java with Records, Sealed Classes, and Pattern Matching.  The Benefits of Using Records The benefits of using Records, Sealed Classes, and Pattern Matching when implementing the Visitor classic design pattern.
  • 4.
    © 2008 HaimMichael 20150805 Prerequisites  Basic Understanding of Record Classes, Sealed Classes, and Pattern Matching in Java.
  • 5.
    © 2008 HaimMichael 20150805 The Programming Problem (1 out of 4)  In many object-oriented systems, we have a class hierarchy (e.g., expression tree, shape hierarchy) that we want to traverse or operate on in different ways - such as evaluating, rendering, or pretty-printing.  If we add new operations directly to these classes, we might unintentionally clutter the new code with unrelated logic. In addition, we will need to modify existing classes whenever adding new operators.
  • 6.
    © 2008 HaimMichael 20150805 The Programming Problem (2 out of 4)  The Visitor classic design pattern aims at solving the following programming problem: How can we define new operations on a set of related object types (e.g., binary tree nodes, shapes, expressions) without modifying their source code and without duplicating logic across types?
  • 7.
    © 2008 HaimMichael 20150805 The Programming Problem (3 out of 4)  The intent of the Visitor classic design pattern according to the Gang of Four: Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.
  • 8.
    © 2008 HaimMichael 20150805 The Programming Problem (4 out of 4)  The Visitor pattern decouples the operations from the object structure, allowing us to define new operations without changing the element classes.
  • 9.
    © 2008 HaimMichael 20150805 The Traditional Implementation (1 out of 4)  Implementing the Visitor classic design pattern without using Record Classes, Sealed Classes, and Pattern Matching will require having an object that plays the role of a visitor. That object will pays a visit to each one of the objects by calling a method (the accept method) on each one of these objects. Inside the accept method, the visit method will be invoked on the Visitor object. The reference of the visited object will be passed over to it.
  • 10.
    © 2008 HaimMichael 20150805 The Traditional Implementation (2 out of 4) public interface Expression { <T> T accept(Visitor<T> visitor); } public interface Visitor<T> { T visit(Number num); T visit(Total total); T visit(Multiplication mul); T visit(Difference diff); } public class Number implements Expression { public final int value; public Number(int value) { this.value = value; } public <T> T accept(Visitor<T> visitor) { return visitor.visit(this); } }
  • 11.
    © 2008 HaimMichael 20150805 The Traditional Implementation (3 out of 4) public interface Expression { <T> T accept(Visitor<T> visitor); } public class Multiplication implements Expression { public final Expression left, right; public Multiplication(Expression left, Expression right) { this.left = left; this.right = right; } public <T> T accept(Visitor<T> visitor) { return visitor.visit(this); } } public class Total implements Expression { ... } public class Subtraction implements Expression { ... }
  • 12.
    © 2008 HaimMichael 20150805 The Traditional Implementation (4 out of 4) public class SimpleVisitor implements Visitor<Integer> { public Integer visit(Number num) { return num.value; } public Integer visit(Total ob) { return ob.left.accept(this) + ob.right.accept(this); } public Integer visit(Multiplication ob) { return ob.left.accept(this) * ob.right.accept(this); } public Integer visit(Difference ob) { return ob.left.accept(this) - ob.right.accept(this); } }
  • 13.
    © 2008 HaimMichael 20150805 The Modern Implementation (1 out of 4)  Implementing the Visitor classic design pattern when using Record Classes, Sealed Classes and Pattern Matching might become simpler.  We will define a method that will take an Expression object that using pattern matching will evaluate it according to its type.
  • 14.
    © 2008 HaimMichael 20150805 The Modern Implementation (2 out of 4) public sealed interface Expression permits Number, Total, Difference, Multiplication {} public record Number(int value) implements Expression {} public record Total(Expression left, Expression right) implements Expression {} public record Difference (Expression left, Expression right) implements Expression {} public record Multiplication (Expression left, Expression right) implements Expression {}
  • 15.
    © 2008 HaimMichael 20150805 The Modern Implementation (3 out of 4) public class Evaluator { public int evaluate(Expression expression) { return switch (expression) { case Number(int value) -> value; case Total(Expression left, Expression right) -> evaluate(left) + evaluate(right); case Multiplication(Expression left, Expression right) -> evaluate(left) * evaluate(right); case Difference(Expression left, Expression right) -> evaluate(left) - evaluate(right); }; } }
  • 16.
    © 2008 HaimMichael 20150805 The Modern Implementation (4 out of 4) public class Program { public static void main(String[] args) { Expression expression = new Multiplication( new Total(new Number(3),new Number(2)), new Total(new Number(6),new Number(4))); System.out.println(new Evaluator().evaluate(expression)); } }
  • 17.
    © 2008 HaimMichael 20150805 The Benefits  The code becomes cleaner and there is no need in the additional accept() method.
  • 18.
    © 2009 HaimMichael All Rights Reserved 18 Questions & Answers Thanks for Your Time! Haim Michael haim.michael@lifemichael.com +972+3+3726013 ext:700 +972+54+6655837 (whatsapp)