The Visitor Pattern


I like the Visitor Pattern. I am not sure why. It is interesting. I have yet to use it in a real application though. I hope to change that someday.

When using the Visitor Pattern, rather than add methods to a set of classes you have written, you add a new type of visitor class to represent a "new method" for these classes (which I will now start to refer to as target classes for the Visitor), and have the visitor class implement a method for each target type (often overloaded on the target type as the first parameter). Using the Visitor works best when the target classes are in a stable hierarchy that doesn't change very often, but new methods are added frequently. An example of this might be a system of Transaction objects which is fairly fixed (credit, debit, transfer, apply interest, etc.) and you are adding a lot of methods to this hierarchy as more features are required.

As an example of the use of the Visitor Pattern, here's some methods we could add to the system of transactions - authorization, logging, create undo state (to be used later to undo a transaction if possible).

Without the visitor, you would add these so called new methods into the classes that you would have been visiting. So each Transaction subclass gets a method to authenticate, to log, and to create undo state.

The point of the Visitor is to encapsulate some policy from the classes being visited (they don't know their UI in this example, so you have a TransactionUIFactory which has the policy to add a UI to the Transactions - maybe it adds a spiffy high end semi transparent anti aliased full color extravaganza, or maybe it adds some lightweight text or minimally graphic thing - and in any case it cleans up the implementation separating the UI concerns from the behavioral aspects of a Transaction anyway - one class has one responsibility, yay if only it really did end up that way but I digress).

Sooooooooo - Let's say we also want to check if some entity has the authority to do a type of Transaction - we could put that in the Transaction classes, but that would be bad since that conflates authority (a policy) with the transaction operation. Better, as with the UI example, to have a TransactionAuthorityChecker. Now we've added the "method" authorize to each Transaction subclass, but we didn't change the Transaction authority at all, we just added a new class implementing TransactionVisitor which you use to check the Authority to do a transaction (the constructor for a TransactionAuthorityChecker would likely take some Principal it uses to authorize, like a User or Certificate object).

What's nice with visitor is that you do not have to modify the Transaction classes themselves to add this new "method" (the accept method already serves as the springboard to call into the visit method in the new TransactionAuthorityChecker class).

Again, if we kept adding new kinds of Transactions, we'd drive the authors of TransactionUIFactory and TransactionAuthorityChecker crazy. We likely won't though, since there aren't zillions of types of Transactions.

Posted: Fri - September 26, 2003 at 01:05 AM      


©