No subject
Fri Aug 6 17:04:17 PDT 2004
interface Visitor
{
void visitElement(Element e);
void visitAttribute(Attribute a);
//etc.
}
class Document
{
void accept(Visitor v);
}
If the user now says:
Document d;
//...
d.accept(myVisitor);
The Document will ensure that myVisitor visits all the
visitable items that are part of the Document
structure. Instead of building all the structure
traversal knowledge into Document, it is typical for
the objects that are part of the structure to also
have accept methods, and for objects like Element to
have their accept methods turn around and call accept
on all of the objects they refer to. So the whole
thing turns into a recursive tree walk.
So Document is responsible for making sure the visitor
visits all the objects that make up the Document, but
Document might get help from Element, Attribute, etc.
by each of those classes defining their own accept
method.
It makes no sense for the accept method to return an
object, and it makes no sense for any of the visit
methods in the Visitor to return an object for a
couple of reasons:
1) Most of the accept methods are called by other
accept methods. The calls are not exposed to the user,
so there is no one there to look at the returned
object who cares.
2) The user just calls the accept method on the
Document. If the user is just going to look at what
Document returns, Document would have to return a
structure just as complex as the Document itself in
order for the user to be able to look at the return
and be able to get access to it.
Visitor is supposed to hide all of the traversal
issues for visiting all the objects in some complex
structure. The Visitor that the user implements knows
nothing about how to get to all of these objects, it
just gets a method invoked on it for each object in
the collection.
BONUS ISSUE
-----------
When you implement the Visitor interface, the code in
the Visitor will find out about each visited object in
the larger structure, but won't find out about how
those objects are related. For instance, for a
Document that contains two Elements, the visitElement
method would be called twice, but the user won't know
if the Elements are peers or if there is a
parent/child relationship without looking into the
Elements. Of course looking into the elements means
implementing the traversal yourself.
This can be dealt with by extending the Visitor
pattern to have push and pop semantics for any entity
that can be a parent in a hierarchy, so the example
interface would become:
interface Visitor
{
void pushElement(Element e);
void popElement();
void visitAttribute(Attribute a);
//etc.
}
Now a user who cares about the element hierarchy can
watch for element pops, while users who don't care
about hierarchy can ignore them and consider
pushElement to mean visitElement.
For example, if visiting two peer Elements the method
invocations the Visitor implementation would see are:
pushElement(A)
popElement()
pushElement(B)
popElement()
While visiting two Elements in a parent/child
relationship would look like:
pushElement(A)
pushElement(B)
popElement()
popElement()
I hope this clears some things up about Visitor. If it
doesn't, or if you have some more questions, please
let me know.
--Paul
__________________________________________________
Do You Yahoo!?
Yahoo! Auctions - buy the things you want at great prices
http://auctions.yahoo.com/
More information about the jdom-interest
mailing list