Monday, July 19, 2010

Advanced usage of Visitor-Pattern

Have you ever used the Visitor Pattern to resolve the specific type of a collection of objects? What you usually do is defining a common interface and add an accept()-method taking the visitor interface and in the implementation invoke the visit()-method from the visitor.

Here is an example for following hierarchy

The INodeElement might look like this:

and the IHeadElement linke this

Later on, in your implementation code you can use the visitor to lookup the concrete type

As you can see there is no typecast needed, so you never get a ClassCastException. However if you look at the example, one major drawback of the visitor pattern is that if the hierarchy is not matching exactly, you have a bunch of empty methods. These methods can lead to confusion and doing nothing or throwing an exception isn't much better than a ClassCastException.

If you have the control over the source, you can easily introduce a new more specific type in your hierarchy to workaround this.

Now you can tag the child elements (in this case we have only one)

and the return type of the list can be changed to a more specific one

Using the new more specific visitor, there are no more unnecessary methods

Problem solved? Yes, if you have the freedom to modify each element for tagging it, when ever you create a child list. Otherwise you should look for a better solution.

Think a short time about, what you really want to do. You want to restrict the list to adding elements only of specific types and allow to query them later, while making sure that no type is forgotten when the code changes. Another possibility to add a visitor is to wrap the list element. To do so, remove the IHeadElementChild interface and the corresponding accept-method from the ITitelElement. Now add an implemention for the IHeadElementChild interface. Create factory method for each element allow in the childlist.

In the implementation of the IHeadElement always add the wrapper to the list, everything else can be left as it is. Now you are completely independent of the class hierarchy. Note that this solution will also work with classes provided by foreign frameworks.

If you already used actifsource to describe and generate your class hierarchy, you can leave the whole work to the generator and gain the advantage of more type-safety and less casts.

No comments:

Post a Comment