The Visitor Pattern

http://www.wikihow.com/Install-a-Doorbell

A design pattern is a generally repeatable solution to a commonly occurring problem in software design. Good to know. Someone asked me this in Zagaku (morning sessions we share some knowledge) and I had no idea why they are actually called patterns. So that’s why.

The one I looked at today was the Visitor Pattern. This is a pattern where one interface (Visitor) defines a computation / operation and another (Visitable) is responsible for providing data access.

It helps your code adhere to the single responsibility principle as if a class is just responsible for holding data, it does not clutter it up with adding computation or additional logic to it and any additional operations can be added externally in the Visitor class.

The reason to use it is given in Head First Design Patterns as:

Use when you want to add capabilities to a composite of objects and encapsulation is not important.

Why use it?

The advantage of using this instead of simply extending a class is that it can handle different data types through method overloading. Annoyingly though, every time a new data type has to be handled it needs to be added to the visitable interface, which is an OCP violation. But if you know there is a definite, relatively small number of data types this might not be such a problem.

A Visitor Example

Here is an example I found online of a tax calculator visitor, explained really well by Derek Banas:

This is the Visitor interface. Handling multiple datatypes through method overloading.

public interface Visitor {
String visit(Liquor liquorItem);
String visit(Tobacco tobaccoItem);
String visit(Necessity necessityItem);
}

Here is a concrete implementation of the Visitor (with a computation for calculating taxes for certain goods):

public class TaxVisitor implements Visitor {
    @Override
public String visit(Liquor liquorItem) {
return "Liquor item: Price with tax: " + Math.round((liquorItem.getPrice() * 0.18) + liquorItem.getPrice());
}

@Override
public String visit(Tobacco tobaccoItem) {
return "Tobacco item: Price with tax: " + Math.round((tobaccoItem.getPrice() * 0.32) + tobaccoItem.getPrice());
}

@Override
public String visit(Necessity necessityItem) {
return "Necessity item: Price with tax: " + necessityItem.getPrice();
}
}

Then there is the Visitable interface which accepts a visitor:

public interface Visitable {
String accept(Visitor visitor);
}

and the concrete implementations of it:

public class Liquor implements Visitable {
private final double price;

public Liquor(double item) {
price = item;
}

public double getPrice() {
return price;
}

@Override
public String accept(Visitor visitor) {
return visitor.visit(this);
}
}
public class Tobacco implements Visitable{
private final double price;

public Tobacco (double item) {
price = item;
}

public double getPrice() {
return price;
}

@Override
public String accept(Visitor visitor) {
return visitor.visit(this);
}
}
public class Necessity implements Visitable {
private final double price;

public Necessity (double item) {
price = item;
}

public double getPrice() {
return price;
}

@Override
public String accept(Visitor visitor) {
return visitor.visit(this);
}
}

These classes are solely responsible for holding data, they should just pass a single data element to the visitor class (how this is done is not important).

It can also be used to traverse complex data structures as the Visitable should be able to guide the visitor through a complex composite structure if necessary.

public class VisitorTest {
TaxVisitor taxCalculator = new TaxVisitor();



Necessity milk = new Necessity(1.99);
Liquor liquor = new Liquor(11.99);
Tobacco tobacco = new Tobacco(19.99);

@Test
public void calculatesPriceWithTaxForMilk() {
assertEquals(milk.accept(taxCalculator), "Necessity item: Price with tax: 1.99");
}

@Test
public void calculatesPriceWithTaxForLiquor() {
assertEquals(liquor.accept(taxCalculator), "Liquor item: Price with tax: 14");
}

@Test
public void calculatesPriceWithTaxForTobacco() {
assertEquals(tobacco.accept(taxCalculator), "Tobacco item: Price with tax: 26");
}
}

A new type of tax calculator can then be created that has different tax levels for these goods and this is the visitor that has to be passed to the Visitable classes.

eg. TaxHolidayVisitor taxHolidayCalculator = new TaxHolidayVisitor();

So that’s the visitor pattern, quite a useful one, but with some limitations so use with caution..

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.