Wednesday, November 05, 2003

Acyclic Visitor

OK, I was reading "Agile Software Development" again and I came across this pattern. I had never heard of it before so it peaked my interest. I have a love/hate relationship with the GoF Visitor pattern. I love it because it helps separate out responsibilities (an object doesn't need to know how to display itself on 4 different displays, it just needs to accept a visitor). But, I hate it since it's so brittle to object structure changes. Well, the acyclic visitor pattern removes my hate! But, the solution in the book is U-G-L-Y. Here's the Java code:
    public void accept(SomeVisitor aVisitor) {
      SpecificVisitor v=(SpecificVisitor)aVisitor;
      try {
        v.visitSpecificObject(this);
      } catch (ClassCastException ex) {
        //no nothing eat the exception
      }
    }

I don't know about you, but to put this code in every object that needs the visitor is yucky. Not only that, but the code requires you to have a different interface for each object and that's even more yucky! It means I will have a lot of interfaces with one method just to get around the static typing system! GROSS! But, all is not lost. If Java implemented a Does Not Understand method, then the solution would become elegant again! Smalltalk has exactly this and it's something I wish Java would have (the proxy objects are getting close). Here's the Smalltalk code:
    SpecificObject>>accept: aVisitor
      aVisitor visitSpecificObject: self

Now, you might ask where is the code if the message is not understood?! You have implemented the plain ole vanilla visitor pattern and the hate is back! Hold on, along with all of the other visit methods, here's one method that I add in to the visitor:
    Visitor>>doesNotUnderstand: aMessage
      ^(aMessage selector beginsWith: 'visit')
        ifTrue: [self "do nothing"]
        ifFalse: [super doesNotUnderstand: aMessage]

We have moved the responsibility of checking if we understand the message from each object that accepts visitors to the actual visitor! We only need to implement the checking in one place. This makes acyclic visitor much more attractive! Now, I do not support unchecked use of doesNotUnderstand:, but when you need it, YOU NEED IT! I thought this was a powerful and simple demonstration of the doesNotUnderstand: message. And I now have a new trick in my bag.

No comments:

Amazon