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.