- solution: create a Visitor class which holds the operation to be
applied to each node
- subclasses will instantiate the operation as needed
- example: consider following structure for simple graphics:
- Added methods to support various inquiries:
- area: compute area of graphic - reasonably general-purpose,
though there are lots of ways to compute this
- all_colors: return set of colors in image - somewhat specialized
- sansHello: does picture contain the text "Hello" - very
specific to a problem
- Issue: adding methods like this takes a general purpose class and makes
it very specific to a particular problem
- Needed: a way to process all items in hierarchy without having to add
methods to those items
- Could set up an iterator and externally, but need to be able to
differentiate between the types of items in the structure
- Solution: set up a visitor designed to visit each sort of item (but do
nothing for each):
public class GraphicVisitor
{
public void execute(Line item) { }
public void execute(Rectangle item) { }
public void execute(Text item) { }
public void execute(Picture item) { }
};
- Add an operation to apply a graphic visitor to Graphic:
abstract void apply(GraphicVisitor visitor);
- Code to apply visitor to Line, Picture:
public class Line {
...
public void apply(GraphicVisitor visitor)
{
visitor.execute(this); // executes Line version
}
}
public class Picture {
...
public void apply(GraphicVisitor visitor)
{
visitor.execute(this); // execute Picture version
// apply visitor to each child:
for (Graphic g : children)
g.apply(visitor);
}
}
- Application: implement tool to collect the colors for lines and rectangles:
public class LineColorCollector extends GraphicVisitor {
protected Set<Int> colors = new Set<>;
public Set<Int> allColors() { return colors; }
public void execute(Line item) { colors.add(item.color()); }
public void execute(Rectangle item) { colors.add(item.color()); }
// no need to override default code for text, picture
};
... in some other class:
void printNumColors(Graphic image) {
LineColorCollector collector = new LineColorCollector();
image.apply(collector);
System.out.println("Number of distinct colors in lines and rectangles: "
+ collector.allColors().size());
}
- When to use:
- object structure contains lots of classes of objects
- need to perform lots of distinct operations on objects in the object
structure
- structure being visited is pretty stable
- application to expressions:
- can retarget compiler by switching visitor object used at runtime