How can the ProcessComponent developers include support of cycle
management in the hierarchy's support for V ISITOR ?
V ISITOR is a controversial pattern. Some developers consistently avoid applying it; others
defend its use and suggest ways to strengthen it, although these suggestions usually add
complexity. The fact is that many design problems tend to accompany the V ISITOR pattern.
The fragility of V ISITOR shows up in the examples in this chapter. For instance, in the
MachineComponent hierarchy, the hierarchy developers decided to differentiate between
Machine nodes and MachineComposite nodes but not to differentiate among Machine
subclasses. If you need to distinguish among types of machines in your visitor, you will have
to resort to using instanceof or another technique to tell which type of machine
a visit() method has received. You might argue that the hierarchy developers should have
included all machine types as well as a catchall visit(:Machine) method in the visitor
interface. But new machine types come along all the time, so this does not appear to be any
Another example of fragility showed up in the ProcessComponent hierarchy.
The developers of the hierarchy are aware of the danger of cycles that lurks within process
flow models. How can the developers convey their concerns to a visitor developer? This may
expose the fundamental problem with V ISITOR : Extending a hierarchy's behavior usually
requires some expert knowledge of the hierarchy's design. If you lack that expertise, you may
step in a trap, such as not avoiding cycles in a process flow. If you do have expert knowledge
of the hierarchy's mechanics, you may build in dangerous dependencies that will break if
the hierarchy changes. For example, note that the FindVisitor class depends on the notion
that a machine's ID number uniquely identifies the machine. If this principle changes so that
identity depends on, say, the containing factory plus the machine's ID, the FindVisitor
class may break with a composite that contains two factories. The division of expertise and
code control can make V ISITOR a dangerous pattern to apply.
The classic case in which V ISITOR seems to work well without creating downstream problems
is language development. When you develop a language parser, you may arrange for the
parser to create an abstract syntax tree, a structure that organizes the input text according to
the language's grammar. You may want to develop a variety of behaviors to accompany these
trees, and the V ISITOR pattern is an effective approach for allowing this. Note, though, that in
this classic case, the visited hierarchy usually has little or no behavior. Thus, all the
responsibility for behavior design lies with visitors, avoiding the split of responsibility that
this chapter's examples must endure.
Like any pattern, V ISITOR is never necessary; if it were, it would automatically appear
everywhere it was needed. For V ISITOR , though, alternatives often provide a sturdier design.