The Visitor design pattern works really well for "recursive" structures like directory trees, XML structures, or document outlines.
A Visitor object visits each node in the recursive structure: each directory, each XML tag, whatever. The Visitor object doesn't loop through the structure. Instead Visitor methods are applied to each node of the structure.
Here's a typical recursive node structure. Could be a directory or an XML tag.
[If your a Java person, imagine of a lot of extra methods to build and maintain the children list.]
class TreeNode( object ):
def __init__( self, name, *children ):
self.name= name
self.children= children
def visit( self, someVisitor ):
someVisitor.arrivedAt( self )
someVisitor.down()
for c in self.children:
c.visit( someVisitor )
someVisitor.up()
The visit
method applies a Visitor object to each node in the structure. In this case, it's a top-down visitor. You can change the structure of the visit
method to do bottom-up or some other ordering.
Here's a superclass for visitors. It's used by the visit
method. It "arrives at" each node in the structure. Since the visit
method calls up
and down
, the visitor can keep track of the depth.
class Visitor( object ):
def __init__( self ):
self.depth= 0
def down( self ):
self.depth += 1
def up( self ):
self.depth -= 1
def arrivedAt( self, aTreeNode ):
print self.depth, aTreeNode.name
A subclass could do things like count nodes at each level and accumulate a list of nodes, generating a nice path hierarchical section numbers.
Here's an application. It builds a tree structure, someTree
. It creates a Visitor
, dumpNodes
.
Then it applies the dumpNodes
to the tree. The dumpNode
object will "visit" each node in the tree.
someTree= TreeNode( "Top", TreeNode("c1"), TreeNode("c2"), TreeNode("c3") )
dumpNodes= Visitor()
someTree.visit( dumpNodes )
The TreeNode visit
algorithm will assure that every TreeNode is used as an argument to the Visitor's arrivedAt
method.