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.
Real-world example
Consider a tree structure with army units. Commander has two sergeants under it and each sergeant has three soldiers under them. Given that the hierarchy implements the visitor pattern, we can easily create new objects that interact with the commander, sergeants, soldiers, or all of them.
In plain words
Visitor pattern defines operations that can be performed on the nodes of the data structure.
Wikipedia says
In object-oriented programming and software engineering, the visitor design pattern is a way of separating an algorithm from an object structure on which it operates. A practical result of this separation is the ability to add new operations to existing object structures without modifying the structures.
Programmatic Example
Given the army unit example from above, we first have the Unit and UnitVisitor base types.
1public abstract class Unit {
2
3 private final Unit[] children;
4
5 public Unit(Unit... children) {
6 this.children = children;
7 }
8
9 public void accept(UnitVisitor visitor) {
10 Arrays.stream(children).forEach(child -> child.accept(visitor));
11 }
12}
13
14public interface UnitVisitor {
15
16 void visit(Soldier soldier);
17
18 void visit(Sergeant sergeant);
19
20 void visit(Commander commander);
21}
Then we have the concrete units.
1public class Commander extends Unit {
2
3 public Commander(Unit... children) {
4 super(children);
5 }
6
7 @Override
8 public void accept(UnitVisitor visitor) {
9 visitor.visit(this);
10 super.accept(visitor);
11 }
12
13 @Override
14 public String toString() {
15 return "commander";
16 }
17}
18
19public class Sergeant extends Unit {
20
21 public Sergeant(Unit... children) {
22 super(children);
23 }
24
25 @Override
26 public void accept(UnitVisitor visitor) {
27 visitor.visit(this);
28 super.accept(visitor);
29 }
30
31 @Override
32 public String toString() {
33 return "sergeant";
34 }
35}
36
37public class Soldier extends Unit {
38
39 public Soldier(Unit... children) {
40 super(children);
41 }
42
43 @Override
44 public void accept(UnitVisitor visitor) {
45 visitor.visit(this);
46 super.accept(visitor);
47 }
48
49 @Override
50 public String toString() {
51 return "soldier";
52 }
53}
Here are then some concrete visitors.
1@Slf4j
2public class CommanderVisitor implements UnitVisitor {
3
4 @Override
5 public void visit(Soldier soldier) {
6 // Do nothing
7 }
8
9 @Override
10 public void visit(Sergeant sergeant) {
11 // Do nothing
12 }
13
14 @Override
15 public void visit(Commander commander) {
16 LOGGER.info("Good to see you {}", commander);
17 }
18}
19
20@Slf4j
21public class SergeantVisitor implements UnitVisitor {
22
23 @Override
24 public void visit(Soldier soldier) {
25 // Do nothing
26 }
27
28 @Override
29 public void visit(Sergeant sergeant) {
30 LOGGER.info("Hello {}", sergeant);
31 }
32
33 @Override
34 public void visit(Commander commander) {
35 // Do nothing
36 }
37}
38
39@Slf4j
40public class SoldierVisitor implements UnitVisitor {
41
42 @Override
43 public void visit(Soldier soldier) {
44 LOGGER.info("Greetings {}", soldier);
45 }
46
47 @Override
48 public void visit(Sergeant sergeant) {
49 // Do nothing
50 }
51
52 @Override
53 public void visit(Commander commander) {
54 // Do nothing
55 }
56}
Finally, we can show the power of visitors in action.
1commander.accept(new SoldierVisitor());
2commander.accept(new SergeantVisitor());
3commander.accept(new CommanderVisitor());
Program output:
Greetings soldier
Greetings soldier
Greetings soldier
Greetings soldier
Greetings soldier
Greetings soldier
Hello sergeant
Hello sergeant
Good to see you commander
Use the Visitor pattern when