This post is part of a series of reviews on the book Design Patterns in Ruby. Check out the Introduction post for a full table of contents along with some generic principles regarding Design Patterns.

The Factory pattern is basically the Template Method applied to object creation, so, instead of choosing which kind of algorithm we want to use, we’ll be choosing what kind of object we want to create.

As you can see, the class diagram looks alot like the Template Method diagram, with the difference of each concrete factory creating a concrete product. To illustrate this we’ll be using a life simulator class called Pond.

#Factories (ponds)
class Pond
	def initialize(number_animals)
		@animals = []
		number_animals.times {|i| @animals << new_animal("Animal #{i}")}
	end

	def simulate_one_day
		@animals.each{|animal| animal.live}
	end
end

class DuckPond < Pond
	def new_animal(name)
		Duck.new(name)
	end
end

class FrogPond < Pond
	def new_animal(name)
		Frog.new(name)
	end
end

#Products (animals)

class Animal
	attr_accessor :name
	def initialize(name)
		@name = name
	end
end

class Frog < Animal
	def live
		puts "Frog #{self.name} is croaking peacefully."
	end
end

class Duck < Animal
	def live
		puts "Duck #{self.name} is quacking like there's no tomorrow."
	end
end

frog_pond = FrogPond.new(3)
frog_pond.simulate_one_day

duck_pond = DuckPond.new(3)
duck_pond.simulate_one_day

All this code is doing is letting the Pond subclasses decide which kind of object they should create.

In Ruby, even classes are objects, so we can pass them around however we like and call methods on them whenever we like, such as new. With that in mind, we can pass in class names (which are treated as Constants in Ruby) to the Pond constructor and create objects directly from it without depending on any factory subclasses, like so:

#Factories (ponds)
class Pond
	def initialize(number_animals, animal_class)
		@animal_class = animal_class
		@animals = []
		number_animals.times {|i| @animals << new_animal("Animal #{i}")}
	end

	def new_animal(name)
		@animal_class.new(name)
	end

	def simulate_one_day
		@animals.each{|animal| animal.live}
	end
end

Let’s move on to something bigger, say we now to simulate entire Habitats with animals and plants too, so we’re not gonna be generating random animals and plants, we have to follow nature’s way and put them in their right habitats. Notice we’re changing our intent from simply choosing which kind of object to create to choosing the right set of objects to create, that’s where the Abstract Factory comes in:

Each concrete factory is responsible for creating its own collection of objects, and that’s exactly what we’ll be doing with our Habitat example. First let’s create the products (plants and animals):

class Plant
	attr_accessor :name
	def initialize(name)
		@name = name
	end
end

class Algae < Plant
	def grow
		puts "Algae #{self.name} grows while floating in the water"
	end
end

class Tree < Plant
	def grow
		puts "Tree #{self.name} grows tall"
	end
end

class Animal
	attr_accessor :name
	def initialize(name)
		@name = name
	end
end

class Frog < Animal
	def live
		puts "Frog #{self.name} is croaking peacefully."
	end
end

class Tiger < Animal
	def live
		puts "Tiger #{self.name} roars fiercely"
	end
end

Now that we have all our products we can start coding habitats, which will be responsible for creating their own type of plant and animal:

class Habitat
	def initialize(number_animals, number_plants, organism_factory)
		@organism_factory = organism_factory
		@animals = []
		number_animals.times {|i| @animals << @organism_factory.new_animal("Animal #{i}")}
		@plants = []
		number_plants.times {|i| @plants << @organism_factory.new_plant("Plant #{i}")}
	end

	def simulate_one_day
		@animals.each{|animal| animal.live}
		@plants.each{|plant| plant.grow}
	end
end

class PondOrganismFactory
	def new_animal(name)
		Frog.new(name)
	end
	def new_plant(name)
		Algae.new(name)
	end
end

class JungleOrganismFactory
	def new_animal(name)
		Tiger.new(name)
	end
	def new_plant(name)
		Tree.new(name)
	end
end


jungle = Habitat.new(1,4, JungleOrganismFactory.new)
jungle.simulate_one_day

pond = Habitat.new(2,4, PondOrganismFactory.new)
pond.simulate_one_day

As you can see, we’re delegating the duty of creating objects to another object through composition, so, when you think about it, the same way the Factory Method is a specialization of the Template Method, the Abstract Factory is a specialization of the Strategy pattern.
Moving on, the same technique we used to elimite factory subclasses before we can use again to eliminate these. Remember, classes are just objects:

class OrganismFactory
	def initialize(animal_class, plant_class)
		@animal_class = animal_class
		@plant_class = plant_class
	end
	def new_animal(name)
		@animal_class.new(name)
	end
	def new_plant(name)
		@plant_class.new(name)
	end
end


jungle = Habitat.new(1,4, OrganismFactory.new(Tiger, Tree))
jungle.simulate_one_day

pond = Habitat.new(2,4, OrganismFactory.new(Frog, Algae))
pond.simulate_one_day

The important thing to remember about both patterns is how they’re different and how they’re alike. The main difference between them is their intent: the Factory Pattern is only worried about a single object to create while the Abstract Factory thinks of what collection of objects to create. In the other hand, they’re alike in the sense that both patterns focus on object creation.