- From: Michael Allen <Michael.R.Allen@Eng.Sun.COM>
- Date: Mon, 16 Nov 1998 18:58:40 -0800 (PST)
- To: www-dom@w3.org
I think one of the key missing features for me would be a Visitor
pattern method on Node. I suggested something like this earlier to this list,
and I might even be able to dig up my past e-mail, which will be much more
detailed than this one.
The justification for a Visitor pattern interface on Node is to remedy
the fact that, given the current implementation, you often have to cast Nodes
back up to whatever specific HTML class they are. Since iterator-like classes,
such as NodeList and NamedNodeMap are constantly returning base Node objects,
the casting costs are quite high, especially in a strongly-typed language like
Java.
Here's the text of my original message to the list:
-- begin --
With all this talk of quickly casting to subclasses from a base class
reference, I wonder if anyone has ever thought of putting Visitor design pattern
functionality into Node? I have also heard the Visitor pattern referred to as
"double dispatch". It would look something like this (in pseudo-Java):
public interface Node {
// rest of node methods and stuff
public void visit(NodeVisitor v);
}
public interface NodeVisitor {
public void visitNode(Node n);
public void visitElement(Element e);
public void visitAttribute(Attribute a);
public void visitData(Data d);
}
And then in the actual implementation:
public class Foo {
public void bar() {
// Somehow this thing gets a Node:
Node n = getTheNode();
MyNodeVisitor visitor = v;
n.visit(v);
}
}
public class MyNodeVisitor implements NodeVisitor {
public void visitNode(Node n) {
// do the right thing for plain nodes
}
public void visitElement(Element e) {
// do the right thing for elements
}
public void visitAttribute(Attribute a) {
// do the right thing for attributes
}
public void visitData(Data d) {
// do the right thing for data
}
}
public class MyElement extends MyNode implements Element {
// ... other element methods ...
public void visit(NodeVisitor v) {
v.visitElement(this);
}
}
public class MyData extends MyNode implements Data {
// ... other data methods ...
public void visit(NodeVisitor v) {
v.visitNode(this);
}
}
The implementations of Node and the descendants of those implementations
each override the visit(NodeVisitor); method and call the appropriate
NodeVisitor method, passing themselves in as parameters. This pattern obviates
the need for any casting; all the type checking is done by the compiler and any
internal type checking mechanisms. To extend this pattern to encompass the HTML
specific classes, you just extend the NodeVisitor interface to take more
methods. To avoid type checking what kind of NodeVisitor a Node has received,
you might make NodeVisitor an abstract base class with an Enumerated type field
which contains an int (or bitfield, maybe) which specifies its type. That way,
subclasses which the base NodeVisitor doesn't cover could check the type of
visitors without doing an instanceof test (which, I believe, does not exist in
C++ anyway; however, I could be wrong, it's been a long time since I did any C++
programming) and cast as appropriate.
The Visitor pattern really excels at quickly and efficiently digesting
structures like the DOM's Node hierarchy, where a program needs to differentiate
by their subclasses a tree of objects which all inheret from the same base
class. It is far more effcient than instanceof/casting tests with big
if-then-else statements, and faster again than checking something like a string
which contains the "name"of the subclass in it (up to 8x faster than the
latter, according to some tests I ran under JDK1.1.6 on my Solaris box). The
only structure that approached it in speed was a switch() statement off of an
Enumerated int field in the object.
-- end --
This message was based off an earlier version of the spec, so some of
the specific data types might be off, but the spirit remains the same.
Thanks for your attention,
Michael Allen
Received on Monday, 16 November 1998 21:58:46 UTC