Acyclic Visitor

CategoryPattern, a variation of VisitorPattern:

Documented in PatternLanguagesOfProgramDesign volume three (1997), chapter 7.

Available online as http://www.objectmentor.com/publications/acv.pdf

It is discussed and developed in ModernCeePlusPlusDesign chapter 10.


"The Acyclic Visitor pattern allows new functions to be added to existing class hierarchies without affecting those hierarchies, and without creating the dependency cycles that are inherent to the GangOfFour VisitorPattern." [...quoted with light editing.]


__ AcyclicVisitor:

The receiver of the Visitor dynamic_casts the Visitor to determine if it is the type of Visitor it will accept, and if so, passes itself to the Visitor.

How is this better than:

An operation or class that will only operate on a specific subtype dynamic_casts the instance to determine if it is of that subtype.

The Visitor pattern has two purposes:

1) Enumeration -> as target of an iteration through a collection of a known set of subtypes

2) Type Determination (CapabilityQuery?) -> determine which subtype we are currently examining.

If there is no need for an enumeration target, and a dynamic_cast is acceptable for the Capability Query, there is no need for the Visitor Pattern.

Does anybody want to comment on this observation? Does it make sense? --DirckBlaskey


I developed AcyclicVisitor independently in designing class frameworks. (JohnVlissides also developed a variation in VisitorInFrameworks.)

In a particular UserInterface framework, a state machine (StatePattern) controlled the software's progress through a dialogue with the user. When the user acts, this can cause an event (CommandPattern) to be sent to the state machine, causing it to change to the next state in the dialogue. But what events might a state receive? And how might it handle these events? Answer: It depends on the application. But I can't recompile the framework every time someone wants to create a custom event in a new application. That's that nasty cyclic dependency.

So I pushed the issue of event-handling onto the application. For each event class the application defined, it needed a corresponding event receiver class. If a particular state needed to respond to a particular kind of event, the state class would inherit from the appropriate receiver. The event would then DynamicCast to the corresponding receiver class, executing the event if the cast was successful.

In another instance, I was creating a diagnostic framework. Diagnostic tests inherited from a test base class (StrategyPattern). Each class of test would generate test-specific status, which could be relayed to the user. But the application needs to be able to use application-specific test classes, with application-specific status classes. And the diagnostic framework needs to be completely decoupled from the UI, which may even have its own completely separate framework.

So for each status class, there is a corresponding status receiver class. Each status class knows what kind of receiver can grok it, and DynamicCasts to it. One status message, one DynamicCast. At least it's better than a list of twenty DynamicCasts in a gigantic if-then-elseif, as the UI code hunts around for a kind of status it knows about.

--TimKing


I recently refactored my way into a situation identical to that Tim describes (quite a testament to the magic of refactoring): State + Command compelled Visitor, and then I had a peloton of cycles to get rid of.

It turns out that AcyclicVisitor as written, translated into JavaLanguage, still has a cycle between each element- Visitor pair. Element subclasses (commands) refer to each Visitor subclass (state) via an interface; each Visitor interface must refer to an element subclass, and we have a cycle. The cycle doesn't affect the framework, but I don't like to tolerate even little local ones.The cycle can be easily removed by having Visitors refer to elements via interfaces, but I had a large number of elements, they were quite simple, and the code bloat of having an interface for each element seemed excessive.

Looking for better solutions I came across UncleBob's Java version, http://www.objectmentor.com/resources/articles/visitor , which has the same issue, perhaps indicated by the bidirectional arrows in the diagram, although not explicitly discussed. (I believe the issue almost goes away in CeePlusPlus if the elements and Visitors see each others' declarations but not their definitions, but I haven't worked through it.)

I settled for using reflection, more or less as described in http://www.javaworld.com/javaworld/javatips/jw-javatip98.html . This completely removes any knowledge of the whole business from the elements. The reflective dispatch can be done in one place in a Visitor superclass. The result is quite economical and easy to follow. The only hitch is that because the visit methods are only called via reflection, code checkers think they're unused.

-- DaveSchweisguth?


CategoryPattern CategoryJava CategoryCpp


EditText of this page (last edited May 6, 2012) or FindPage with title or text search