[Newbies] Design with Visitor

Ron Teitelbaum Ron at USMedRec.com
Thu May 25 18:14:56 UTC 2006


Hi Mathieu,

I've been thinking about how to respond to your question.  My first thought
was to jump right in and help, but since this is a home work assignment it
is probably best to help in a round about way.  What I didn't want to do was
to discourage others that are working on homework from asking questions.

So in order to help you I propose the following.  I will help to explain the
patterns you mentioned, and I will critique your solution, all without
helping you solve the problem you are trying to solve, so that you can
benefit from doing and learning from your homework assignment.

First the critique:  I really don't like your implementation of using a
dictionary to handle your collection.  It seems to me that you are trying to
accomplish something but I don't see what the benefit of that implementation
is.  Can you tell me what functionality the dictionary adds?  What is the
benefit of the dictionary over a simple collection?

The visitor pattern is a very useful and translates into passing an object
(the visitor) around.  The idea here is that the functionality that is
needed can be written into the visitor and that way functionality can be
added without modifying the objects that it visits.  Some people do modify
the visited objects to double dispatch methods back to the visitor in order
to control which methods are called on the visitor.

So examples are usually good so let's try a visitor example.  Say we have a
sales tax rate for different states.  We would like to build a simple sales
tax object that is able to calculate the taxes that need to be paid for each
product that is sold.  The tax rules for each state are encoded in visitor
objects but the visitor is passed to the product to calculate the tax.  Each
product may have a different requirement for taxing, say food has one tax
rate and regular goods have another and luxury items have another tax.

This could be accomplished without modifying the object if each object could
respond to product type in which case our tax object could be called by
passing it around.

	ShoppingBag>>calcTax
		"return to the sender the calculated tax for the contents of
the shopping bag for the shopping bags state"
		aState := self myState.
		"find the appropriate visitor "
		aVisitor := StateTax forState: aState.
		^aVisotor calcTax: self.
	
	StateTax>>calcTax: aShoppingBag
		"return to the sender the calculated tax of all items in
aShoppingBag"
		^aShoppingBag contents inject: Float zero into: [:aSum
:anItem |
			aSum := aSum + (self taxFor: anItem)
		].
	
	StateTax>>taxFor: anItem
		"return the tax for anItem type"
		anItem taxType isNoTaxProduct  "food"
		    ifTure: [^Float zero].
		taxRate := (anItem taxType isLuxuryTaxProduct)
		    ifTrue: [self luxuryTaxRate]
		    ifFalse: [self regularTaxRate].
		^anItem baseCost * taxRate

	Ok this is not really the best way to do thing since it would be
better to have a double dispatch way to respond to taxRate.  Instead by
modifying the visited objects with an accept type method we can send the
method back to the visitor.
	
	Product>>taxRate: aVisitor  "this is an accept method"
		"return the tax rate for this product type"
		^aVisitor regularTaxRate
	Product subclass: LuxuryProduct>>taxRate: aVisitor
		"return the tax rate for this product type"
		^aVisitor luxuryTaxRate
	Product subclass: TaxFreeProduct>>taxRate: aVisitor
		"return the tax rate for this product type"
		^Float zero

This changes the visitor method taxFor: to the following
	
	StateTax>>taxFor: anItem
		"return the tax for anItem type"
		
		^anItem baseCost * (anItem taxRate: self)

You can see that each subclass of StateTax now simply has to respond to the
three tax rates.

To summarize you can use the visitor method to add functionality to an
object without modifying it or by adding a double dispatch modification the
functionality stays with the new visitor object but is controlled by the
visited objects.  

This is particularly useful for printing!  

The example assumes that you can create a method to find the proper StateTax
subclass to use as a visitor, and a factory method to create products of the
proper subclass of Product.

I hope that helps with visitor, if not please feel free to ask questions.

Happy coding!!

Ron Teitelbaum
President / Principal Software Engineer
US Medical Record Specialists
Ron at USMedRec.com 

> From: math
> Sent: Thursday, May 25, 2006 10:22 AM
> 
> > Subject: Design with Visitor
> > From: "Mathieu SUEN" <mathk.sue at gmail.com>
> > Date: Wed, 24 May 2006 23:14:58 +0200
> > To: beginners-bounces at lists.squeakfoundation.org
> >
> > Hi squeakers,
> >
> > I have to build  a lite code for home work.
> > The objective is to gave to user a possibility to store his sport
> > performance.
> >
> > So I have design a Class Performance(with PerformanceCollection) and I
> > wanted to let things like TimeLaps, Date, Distance, and so on.
> > for a later implementation (if we wanted to add others).
> >
> > So I provide a Measure abstract  class.
> >
> > Hence I add a dictionary in my Performance with the class for key and
> > the instance for value:
> >
> > for example:
> >
> > Performance>>addMeasure: aMeasure
> >           dictionaryOfMesure at: aMeasure class put: aMeasure
> >
> > Now I have to bring them in a Seaside UI so I guess that Visitor Pattern
> > ( ;-) ) can help me but my complex structure mess my brain.
> > So I ask you if you think that can be possible(and how) or other pattern
> > can be more suitable for this problem.
> >
> > Thank you for your attention (:
> > _______________________________________________
> > Beginners mailing list
> > Beginners at lists.squeakfoundation.org
> > http://lists.squeakfoundation.org/mailman/listinfo/beginners
> >
> >
> Thinking forward I see that 2 Performance instance couldn't be compare
> so befor asking how to print them I will think about a other structure.
> I think I will use Builder or Factory Method pattern.
> 
> Thanks
> _______________________________________________
> Beginners mailing list
> Beginners at lists.squeakfoundation.org
> http://lists.squeakfoundation.org/mailman/listinfo/beginners



More information about the Beginners mailing list