[PersonalPattern] (This page assumes knowledge of the VisitorPattern) *You want to implement the VisitorPattern, as described in DesignPatterns by the GangOfFour. *You are working in a language that supports the #perform: method (Java or Smalltalk). *You can't or don't want to add accept methods to your target classes, and/or *You want some visit methods to apply to a hierarchy of subclasses. ''Therefore'', implement a SelectorGeneratingVisitor. *When the visitor visits an object, it generates its own visit selector based on the name of the object's class. If the visitor does not implement a method with that selector, it tries a selector based on the name of the next higher superclass, repeating until a valid selector is generated or visitObject: is reached. The generated selector is then performed with the object as the argument. *This avoids the need to modify target classes, and lets visit methods be inherited by subclasses. ''Sample code'' Visitor>visit: anObject | selector | selector := self generateSelector: anObject ifNone: [^self error: 'No visit selector']. ^self perform: selector with: anObject Visitor>generateSelector: anObject ifNone: aBlock | class selector | class := anObject class. [class = nil ifTrue: [^aBlock value]. selector := ('visit' , class name , ':') asSymbol. self respondsTo: selector] whileFalse: [class := class superclass]. ^selector Create concrete visitor classes by subclassing Visitor and coding methods such as #visitNumber:, #visitString:, and #visitOrderedCollection: ---- These options require a little more bookkeeping, but compare for clarity and speed: Visitor>visit: anObject | class | class := anOject class. class = Integer ifTrue: [^self visitInteger: anObject]. class = Number ifTrue: [^self visitNumber: anObject]. class = String ifTrue: [^self visitString: anObject]. class = OrderedCollection ifTrue: [^self visitOrderedCollection: anObject]. self error: 'Cannot visit ', class printString or Visitor>visit: anObject self perform: (self visitSelector: anObject) with: anObject Visitor>visitSelector: anObject ^self visitDictionary at: anObject class ifAbsent: [#visitError:] Visitor>visitError: anObject self error: 'Cannot visit ', anObject class printString Visitor>visitDictionary visitDictionary isNil ifTrue: [visitDictionary := Dictionary new at: Integer put: #visitInteger:; at: Number put: #visitNumber:; at: String put: #visitString:; ...; yourself]. ^visitDictionary ---- I like 'em (especially #visitError:). They have the progressive flavor of YAGNI and DTST (YouArentGonnaNeedIt and DoTheSimplestThingThatCouldPossiblyWork). If you at some time run into the problem of wanting a visit method to apply to all subclasses, you might (at that time) want to move on to generating the selectors to give you that capability. As in your example, you could dynamically cache the selectors for speed. --StanSilver !Visitor methodsFor: 'visit'! visit: anObject ^self perform: (self visitSelector: anObject class) with: anObject! visitSelector: aClass ^self selectorDictionary at: aClass ifAbsentPut: [self generateValidSelector: aClass]! generateValidSelector: aClass | class selector | class := aClass. [selector := self generateSelector: class. self respondsTo: selector] whileFalse: [class = Object ifTrue: [^#visitError:]. class := class superclass]. ^selector! generateSelector: aClass ^('visit' , aClass name , ':') asSymbol! selectorDictionary selectorDictionary isNil ifTrue: [selectorDictionary := Dictionary new]. ^selectorDictionary! visitError: anObject self error: 'Cannot visit ' , anObject class printString! ----- This could also be done in Java, using the Reflection library.