Please open CursorDemo.lava in LavaPE.
Please open Visitor.lava in LavaPE.
Iterators / cursors / visitors provide ways to hide and separate aggregate/container objects from sequential algorithms that run through the individual members of those containers. See also the introduction to our repetitive computation samples.
See [8] for an extensive discussion of the iterator/cursor and visitor design patterns. The C++ Standard Template Library STL (see http://www.sgi.com/tech/stl/) provides further examples of various kinds of iterators/cursors.
An Iterator (also called cursor) allows you to walk sequentially through a collection of objects of the same type in some order that is specific for the respective cursor/iterator. After each step (performed by a "next" operation) you may fetch and process the "current" element object of the collection. A "done" member function or variable tells you when you are finished.
"Visitor" is another design pattern that serves for walking through the elements (or "nodes") of a composite object in some order which will not be sequential generally. The elements of a composite object may have different types. In the typical case the composite object is a tree structure, and the visitor walks recursively through this tree and performs operations on the tree nodes. You can have several categories of operations on the tree nodes. Each of these is expressed by a specific derived class of a common "Visitor" base class. You can easily add further operation categories by defining corresponding Visitor sub-classes, without changing the basic tree structure. This is achieved by putting these operations into the Visitor sub-classes rather than the tree node sub-classes.
Cursor/iterator:
The Cursor/iterator sample and the Visitor sample use the same tree structure from include file Tree.lava. The tree nodes (class TreeNode) inherit two attributes, a string str and an integer n, from class TreeData. The TreeCursor class walks in preorder through the tree and displays the contents of str and n.
Look at the implementation of the Cursor operation next in class TreeCursor and note that it is rather tedious, error-prone and unnatural to sequentialize the tree traversal using a cursor/iterator. Recursive traversal is much simpler and much more elegant, as the visitor sample shows. The cursor/iterator traversal would be acceptable only if it would allow you to easily inherit/reuse an existing cursor-based algorithm.
Run the sample program.
Visitor:
The visitor sample uses the same tree structure as the cursor/iterator sample. The basic Visitor class has an abstract virtual type R for the result parameter of its (abstract) evaluate function. The concrete Visitors StringVisitor and IntVisitor assign the concrete Types String and Integer to R, respectively, and implement evaluate in quite different ways.
Note how the initiator VisitorDemo creates the two kinds of visitors and applies them to the same tree structure. Look at the implementations of StringVisitor::evaluate and IntVisitor::evaluate and note how the tree traversal is expressed by recursive invocations of evaluate.
Run the sample program.