xom-interest AT lists.ibiblio.org
Subject: XOM API for Processing XML with Java
List archive
- From: Johannes Döbler <jd AT aztecrider.com>
- To: xom-interest AT lists.ibiblio.org
- Subject: Re: [XOM-interest] Tree walking
- Date: Fri, 20 Sep 2002 12:02:41 +0200
Visitor is straightforward to implement (see below)
Then the first NodeVisitor example could be the Serializer (with the pleasant side-effect that the ugly method "public void write(TreeNode node) throws IOException"
would vanish).
I'm somewhat familiar with the visitor pattern. I did explore it when I was first designing XOM. I'm still not convinced it really fits the XML problem space well. I don't like adding the extra method to Node just to support this. I may be wrong here. So far nobody's shown me convincingly how Visitor would make their life easier than using the more traditional navigation techniques. I'm inclined to agree with the DOM FAQ here:
Visitor was considered for inclusion in the Traversal module of the Level 2 DOM. There are negative as well as positive consequences to implementing the Visitor pattern. One of Visitor's advantages over Iterator is that Visitor can handle structures where the objects don't share a common ancestor class, which is not an issue when everything you're looking at is derived from Node. Since most of the things a Visitor could do can be emulated with a switch statement driven by an iterator, we decided to defer this issue.
Or at least I agree until someone shows me how much easier visitor would make important operations.
It's also a question of programmer familiarity. I think Visitor is one of those issues like interfaces vs. classes, push vs. pull, and pointers vs. stack variables, where the more advanced solution may be marginally better and more extensible for some uses, but really exceeds a lot of working programmers' comfort level. The level of abstraction and indirection can just get too high. Putting the client more in control is a lot more comfortable for most programmers since they can more easily see and visualize how the code flows. I am willing to trade some level of extensibility and generality in exchange for simplicity.
+-----------------------+------------------------+-------------------+
| Elliotte Rusty Harold | elharo AT metalab.unc.edu | Writer/Programmer |
+-----------------------+------------------------+-------------------+
Just if someone wants to learn more about visitor, browse http://www.swe.uni-linz.ac.at/research/deco/designPatterns/Visitor/Visitor.abstract.html
Here is some argumentation in favour of Visitor.
If you have a tree of node objects like in the case of DOM, XOM etc. there is always the need to recursivly iterate though the tree in a generic way.
Take the Serializer class as example, which traverses the tree and prints out a XML document.
Now look at Serializer.write(Element element): It contains a loop to output its TreeNode children.
Depending on the concrete type of each child the appropriate method write(Element), write(Text), write(Comment) etc. has to be called.
This decision is implemented in Serializer.write(TreeNode) which contains a series of instanceof instructions to determine the concrete type, cast down the node and pass it to the appropriate method. Such a switch-structure to cast down to a concrete type is almost ever a sign for a missed change to use polymorphism and OO principles.
If you feel the need to avoid a method like Serializer.write(TreeNode) then there are two solutions:
- add a method for the requested operation directly to the TreeNode interface. (In the example this would be something like "TreeNode.write(Writer out)"
Disadvantage: serializing will not be the only task which iterates through the tree. If for all these possible tasks an own method is added to the TreeNode interface then things will get clumsy soon. So factoring out the serialize task into an own class is sure the way to go,
- use the Visitor pattern: In fact Visitor is just the reusable and extensible OO implementation of that switch instruction to determine the the concrete type of a tree object and invoke some special operation on it. It is used to make methods like Serializer.write(TreeNode) superfluous.
Naturally the way how Serializer is implemented now works.
But think of additional classes which iterate through the tree and perform a operation on its nodes. Each of them will contain a method which will exactly look like Serializer.write(TreeNode). With Visitor you would write this functionality once and could simply use them in each iterator task. Thats all.
Johannes
- Re: [XOM-interest] Tree walking, Johannes Döbler, 09/20/2002
Archive powered by MHonArc 2.6.24.