- A Different Kind of Duck Typing
- The Template Method Strikes Again
- Parameterized Factory Methods
- Classes Are Just Objects, Too
- Bad News: Your Program Hits the Big Time
- Bundles of Object Creation
- Classes Are Just Objects (Again)
- Leveraging the Name
- Using and Abusing the Factory Patterns
- Factory Patterns in the Wild
- Wrapping Up
The Template Method Strikes Again
One way to deal with the “which class” problem is to push the question down onto a subclass. We start by building a generic base class, a class that is generic in the sense that it does not make the “which class” decision. Instead, whenever the base class needs a new object, it calls a method that is defined in a subclass. For example, we could recast our Pond class as shown below so that it relies on a method called new_animal to produce the inhabitants of the pond:
class Pond def initialize(number_animals) @animals = [] number_animals.times do |i| animal = new_animal("Animal#{i}") @animals << animal end end def simulate_one_day @animals.each {|animal| animal.speak} @animals.each {|animal| animal.eat} @animals.each {|animal| animal.sleep} end end
Next we can build two subclasses of Pond—one for a pond full of ducks and the other for a pond hopping with frogs:
class DuckPond < Pond def new_animal(name) Duck.new(name) end end class FrogPond < Pond def new_animal(name) Frog.new(name) end end
Now we need simply choose the right kind of pond, and it will be full of the right kind of creatures:
pond = FrogPond.new(3) pond.simulate_one_day
And we get all sorts of slimy green goings on:
Frog Animal0 says Crooooaaaak! Frog Animal1 says Crooooaaaak! Frog Animal2 says Crooooaaaak! Frog Animal0 is eating. Frog Animal1 is eating. ...
Although I won’t show it here, we could also create a subclass of Pond whose new_animal method produces a mix of both ducks and frogs without much trouble.
The GoF called this technique of pushing the “which class” decision down on a subclass the Factory Method pattern. Figure 13-1 shows the UML diagram for this pattern, which includes two separate class hierarchies. On the one hand, we have the creators, the base and concrete classes that contain the factory methods. On the other hand, we have the products, the objects that are being created. In our pond example, the creator is the Pond class, and the specific types of ponds (like DuckPond and FrogPond) are the concrete creators; the products are the Duck and Frog classes. While Figure 13-1 shows the two products sharing a common base class (Product), our Duck and Frog are not actually blood relatives: They simply share a common type because they implement a common set of methods.
Figure 13-1 Class Diagram for the Factory Method pattern
If you stare at Figure 13-1 long enough, you may discover that the Factory Method pattern is not really a new pattern at all. At its heart, this pattern is really just the Template Method pattern (remember Chapter 3?) applied to the problem of creating new objects. In both the Factory Method pattern and the Template Method pattern, a generic part of the algorithm (in our pond example, its day-to-day aquatic existence) is coded in the generic base class, and subclasses fill in the blanks left in the base class. With the factory method, those filled-in blanks determine the class of objects that will be living in the pond.