views:

1152

answers:

5

Duplicate of: When Should I Use The Visitor Design Pattern

Why would someone want to use the visitor pattern? I've read a couple of articles, but I'm not getting something.

If I need a function to bill a custom, I could use

Custom.Accept(BillVisitor)

or something like

Bill(Customer)

The second is less complex, and the Bill function is still separated from the Customer class. So why would I want to use the visitor pattern?

+8  A: 

The issue arises when you have a complex structure, i.e., a hierarchy or something else that's not simply linear. When you can't simply iterate over the structure, a visitor is very handy.

If I have a hierarchy (or tree), each Node has a list of children. When I want to apply a process to every node in the tree, it's pleasant to create a Visitor.

A Node can then apply the Visitor to itself, and each of its child Nodes. Each child, transitively, does the same (apply the Visitor to itself and then any children).

This use of a Visitor works out very nicely.

When you have a super-simple data structure, Visitor doesn't add a lot of value.

S.Lott
+2  A: 

In both case, the visitor is separated from the customer class. The advantage would be if you wanted to abstract the visitor from the caller class as well. In the second case the calling class has to know about billing. You could instead have another routine somewhere that would return an IVisitor. The calling code could then call Custom.Accept(IVisitor) and not know anything about what the visitor is doing.

Basically in this case and the case the S.Lott mentioned, you can think of the visitor like a delegate. It's a function that you can pass around like an object and use where needed.

Jacob Adams
+1  A: 

Another nice perk of visitors, is they are easy to extend, and if your language allows it, you can even use lamdbas to clean things up.

Robert Gould
A: 

Visitor pattern is a hack for languages that don't support multiple dispatch directly (language like C++ and Java only support single dispatch based on object. Multiple dispatch is supported by CLOS). In this case, if you want both Bill and Customer to be polymorphic, you'll have to use two interface, BillVisitor and Customer in single dispatch languages. For example: the implementation of accept is typically:

void accept(BillVisitor visitor) { visitor.bill(this); } // java syntax

Notice here, both Customer#accept and BillVisitor#bill can be overridden by their respective subclasses, resulting very rich combination of run-time behavior that cannot be achieved otherwise. It's really a superset of what most other people described here as a substitute of closure to apply funtionality to complex data structures.

ididak
+1  A: 

In my CAD/CAM application I have Paths and Collections of Paths (PathList). Sometimes I have to generate a collection of shapes. Not only I have to generate this particular collection of shapes I have to include it with another collection of shapes. I often need a dozen or more parameters to convey all the information needed to do the calculations.

All shape calculations (simple or complex) in my CAM are funneled a PathList that is sent out to the different machines.

With this design it would best to have some setup that involves adding the result to a single collection.

The Path Visitor fits this nicely. Each shape calculation is encapsulated into it's own class with the properties as complex as the needed.

So the Kitchen Hood Visitor may had 8 shapes to the Pathlist

While the Kitchen Counter Visitor adds 6 shapes.

The drawer Visitor adds a few more.

Then I pass out the resulting PathList to the rest of the system like any other shape generator.

I easily have options by adding another visitor or not running some. For a guy who only wants a counter and drawers, I only need to run two visitors.

The resulting code is very readable which is important when I have revisit this area 3, 5, or 10 years down the line. In addition because of encapsulation changes to one visitor have minimal if any impact on other visitors.

In addition I now have a standardized design pattern to add any new functionality to a PathList by implementing the visitor pattern.

For example it used to be that our property editor only worked on a single path. When we changed to editing multiple paths it was easy to implement custom visitors to do global changes to all paths. It was more readable then using for loops inside of delegates.

But ultimately it comes down to judgment and preference.

RS Conley