-
Visitor interface
Defines visit methods for all types that could be visited.
-
Visitor implementations
Defines visit behavior for different types.
-
Element interface
Defines accept method to accept visitor interface.
-
Element implementations
Accept visitor and invoke its visit behavior. May include some conditionto decide whether to accept the visitor.
-
Element collections
Collection of element interfaces. Iterate element and invoke their accept behavior.
When we need to add new behaviors to elements. We can simply define new visitor imlementations with new visit behaviors. So element classes don't have to be changed.
Groovy example
/*
* visitor.groovy
*/
interface Visitor {
void visit(Employee employee)
void visit(Boss boss)
}
interface Element {
void accept(Visitor visitor)
}
class Employee implements Element {
private int payment = 22000
private int vacation = 0
private String name
private boolean inOffice = true
public Employee(String name) {
this.name = name
}
public void accept(Visitor visitor) {
if (inOffice) {
visitor.visit(this)
}
}
public int getPayment() {
return payment
}
public void setPayment(int payment) {
this.payment = payment
}
public int getVacation() {
return vacation
}
public void setVacation(int vacation) {
this.vacation = vacation
}
public String getName() {
return name
}
public void leaveOffice() {
inOffice = false
}
}
class Boss implements Element {
@Override
void accept(Visitor visitor) {
visitor.visit(this)
}
}
class PaymentVisitor implements Visitor {
public void visit(Employee employee) {
employee.setPayment(employee.getPayment() + 3000)
}
@Override
void visit(Boss boss) {
//do something
}
}
class VacationVisitor implements Visitor {
public void visit(Employee employee) {
employee.setVacation(employee.getVacation() + 3)
}
@Override
void visit(Boss boss) {
//do something
}
}
class Employees {
private LinkedList<Employee> _employees = new LinkedList<>()
public accpet(Visitor visitor) {
for (def employee : _employees) {
employee.accept(visitor)
}
}
public void add(Employee employee) {
_employees.add(employee)
}
public String getVacationAndPayment() {
StringBuilder builder = new StringBuilder()
for (def employee : _employees) {
builder.append("name: " + employee.getName())
builder.append("\n")
builder.append("payment: " + employee.getPayment())
builder.append("\n")
builder.append("vacation: " + employee.getVacation())
builder.append("\n")
}
return builder.toString()
}
}
def main() {
def emplyees = new Employees()
def dude = new Employee("Dude")
emplyees.add(new Employee("John"))
emplyees.add(new Employee("Mary"))
emplyees.add(dude)
println(emplyees.getVacationAndPayment())
println(dude.getName() + " left the office!\n")
dude.leaveOffice()
println("Here comes the PaymentVisitor!")
emplyees.accpet(new PaymentVisitor())
println("Here comes the VacationVisitor!")
emplyees.accpet(new VacationVisitor())
println(emplyees.getVacationAndPayment())
}
main()
Result
name: John
payment: 22000
vacation: 0
name: Mary
payment: 22000
vacation: 0
name: Dude
payment: 22000
vacation: 0
Dude left the office!
Here comes the PaymentVisitor!
Here comes the VacationVisitor!
name: John
payment: 25000
vacation: 3
name: Mary
payment: 25000
vacation: 3
name: Dude
payment: 22000
vacation: 0