Skip to Content.
Sympa Menu

gang-of-4-patterns - Re: [gang-of-4-patterns] Visitor Pattern

gang-of-4-patterns AT lists.cs.illinois.edu

Subject: Design Patterns discussion

List archive

Re: [gang-of-4-patterns] Visitor Pattern


Chronological Thread 
  • From: Roman Neuhauser <neuhauser AT sigpipe.cz>
  • To: Lívio Cipriano <lcipriano AT iol.pt>
  • Cc: gang-of-4-patterns AT cs.uiuc.edu
  • Subject: Re: [gang-of-4-patterns] Visitor Pattern
  • Date: Sun, 20 Aug 2006 02:28:42 +0000
  • List-archive: <http://lists.cs.uiuc.edu/pipermail/gang-of-4-patterns>
  • List-id: Design Patterns discussion <gang-of-4-patterns.cs.uiuc.edu>

#
lcipriano AT iol.pt
/ 2006-08-19 11:30:35 +0100:
> ----- Original Message -----
> > #
> > lcipriano AT iol.pt
> > / 2006-08-19 10:48:13 +0100:
> > > I would like to find a pattern, maybe using the Visitor one, that can
> > > be used to traversal a tree.
> >
> > What is your question?
>
> The original Visitor pattern only addresses the "application" of the
> Visitor
> to one Node (in a tree structure). Of course that was only an example,
> cause
> the basic utility of this pattern is to add operations to a set of related
> Classes.

The GoF book discusses using iterators for the traversal on p. 336
("Visiting across class hierarchies"), and has example code on
p. 338 and 341 which puts the traversal responsibility in the tree
structure (nonleaf elements call accept() on their children).

The three possible places to put the traversal responsibility (the
visitor, the composite, an iterator) are discussed on p. 339 ("Who
is responsible for traversing the object structure?")

> My problem is that I've a tree structure, I've Visitores and I need to
> traversal the tree applying the Visitores, so I'm looking for an example
> how
> to do it. Some idea?

class visitor(object):
def visitComponent(self, node):
for child in node.getChildren():
child.accept(self)

or:

class component(object):
def accept(self, visitor):
for child in self.children:
child.accept(visitor)
visitor.visitComponent(self)

or:

class component(object):
def __iter__(self):
return iterator(self.children)

class iterator(object):
def __init__(self, nodes):
self.index = 0
self.nodes = nodes
def __iter__(self):
return self
def next(self):
if self.index >= len(self.nodes):
raise StopIteration
self.index = self.index + 1
return self.nodes[self.index]

Which is appropriate for you depends on which parts of your software
vary.

If all your visitors can work with a single traversal method,
you can put the traversal in the composite's accept(). It makes for
clean, uniform, single-purpose code, unfortunately inflexible.

If the traversal method varies with the visitor then it's better to
put the traversal in the visitor. Visitors that work around an
inappropriate traversal method need to maintain more state, which
makes them more complicated (plus the memory requirements).
The traversal code may clutter the visitor and/or cause redundance.

Finally, the iterator approach frees the visitor from the traversal
responsibility, sometimes making it possible to reduce the visitor
to (basically) a set of callbacks. OTOH it may obscure the code
a bit.

Iterators may present a problem in staticly typed languages, but see
eg. http://www.boost.org/doc/html/variant.html

--
How many Vietnam vets does it take to screw in a light bulb?
You don't know, man. You don't KNOW.
Cause you weren't THERE. http://bash.org/?255991




Archive powered by MHonArc 2.6.16.

Top of Page