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