views:

133

answers:

2

Are factory methods used in Smalltalk, and if so, how should one go about writing one, as opposed to how they would in Java, for example? Thanks.

+8  A: 

In a factory pattern we instantiate some subclass without naming it. Consider a pizza factory and hierarchy:

Pizza
  PepperoniPizza
  CheesePizza
  ...

We'd like instantiate a pizza subclass without knowing it's class name. For example:

  pizza := Pizza flavor: 'cheese' size: 12 inches

answers the right subclass of pizza, with it's size filled in.

Now in Java or C++ one would probably do a large 'switch' statement to compare on different string names. Each time we added a new subclass of Pizza, we'd need to remember to add to the master switch statement. See Wikipedia article for typical examples.

Not so in Smalltalk, where classes are first class objects, so we can iterate down the class hierarchy, asking each subclasses to match. For example:

Pizza class>>flavor: aString size: anInteger
  matchingClass := self subclasses detect: [:first | first matching: aString].
  ^matchingClass new size: anInteger.

And whenever we implement a new subclass of pizza, we implement one method to do the factory matching:

CheesePizza class>>matching: aString
  ^aString = 'cheese'
PepperoniPizza class>>matching: aString
  ^aString = 'pepperoni'

No central switch statement to maintain. Just objects!

Alan Wostenberg
"Now in Java or C++ one would probably do a large 'switch' statement to compare on different string names" --- Your Smalltalk example with the 'matching' is fairly equivalent to using Java reflection and dynamic class loading, which is what I do in Java in all but the most trivial cases of a factory. I've read before some things to the effect of "if you have big switch statements you're doing OO wrong". Wish I could find a reference now.
Stephen P
A: 

First of all, in Smalltalk you have named constructors. In fact, classes are objects and "constructors" are just methods defined on the class that happen to return new instances. Many uses of factory methods in other languages can be covered that way.

For example

Thing class >> withName: aString
    ^ dictionaryOfAllThings 
        at: aString 
        ifAbsentPut: (self new name: aString; yourself)

which get a thing by name, and only creates a new thing if a thing with that name does not yet exist.

Adrian