Design Patterns in Ruby : The Factory Method

2
Categories: Design Patterns
Posted on: 26th April 2009 by: kitallis

This is an article series on implementing programming Design Patterns in Ruby. This is the second part of the series and here’s a link to the last article on the Template Design Pattern.

The Factory Method Pattern

I have to this say this, but Wikipedia has a pretty good explanation and a Ruby implementation for this Creational Pattern, so I’d be focusing mainly upon the general idea of why this pattern is similar to the Template Method pattern and explain some of its defined variants.

What is it?

It is a Creational design pattern : defining how created objects should be mechanised as per the pattern as chances are there might be design problems with bad object control.

When is it needed?

It’s all about picking the right class. It’s pretty much like the Template Method pattern. In the Template Method pattern there was a generic portion which was stored in a base class and the other fill-in-the blanks were controlled by the subclasses and the Template method drove certain methods so that they needn’t be explicitly called. Here, with the Factory Method those subclasses determine what objects to be created. So the Factory Method is for creating objects as Template Method was for driving an algorithm.

How is it done?

Here’s my dummy implementation for the Factory Method pattern.

module Factory
  def draw
     raise NotImplementedError, "You need to call this method, brotha"
  end
end

class Circle
 include Factory
 def draw
   # Clear Screen
   # Draw Circle
 end
end

class Square
 include Factory
   def draw
     # Clear Screen
     # Draw Square
   end
end

class Tetrahedron
  include Factory
  def draw
    # Clear Screen
    # Draw Square
  end
end

class RandomShape
  include Factory
    def draw
      # Clear Screen
      # Draw any shape apart from the above three
    end
end

class CreateShape
  def self.CallShapes(shape)
    case(shape)
      when "Circle"
        Circle.new
      when "Square"
        Square.new
      when "Tetrahedron"
        Tetrahedron.new
    else
      RandomShape.new
    end
  end
end

More precisely, the Shape module is for defining the Draw method which raises a predefined NotImplementedError exception object. Circle, Square and Tetrahedron are the subclasses which call the Shape module and are called by the Factory Method – CallShapes for creating objects out of them to be selected as per the user call.

This pattern is used when a class (theCreator) does not know beforehand all the subclasses that it will create. Instead, each subclass (the Concrete Creator) is left with the responsibility of creating the actual object instances.
The example shown here is specifically a Parametrized Factory Method, that takes in certain parameters from the user and creates objects accordingly.

Abstract Factory Method can pretty much be understood by this UML diagram

Factory Method UML

(Courtesy : Design patterns in Ruby )

The basic idea behind Abstract Factory Methods are to form a group of factories that are compatible with each other. According to the diagram, there are Two Factories encapsulated by one single Abstract factory and each concrete factory produces its set of compatible products. And that’s pretty much what Abstract Factory Methods are.

Taking an example from the Book, the ActiveRecord library uses a form of this kind of pattern.
ActiveRecord has an adapter class for each different kind of database that it uses like MySQL, Oracle. To set up the connection the user name, password, and a string containing the name of the adapter that ActiveRecord uses is supplied. So we enter ‘mysql’ if we want to talk to a MySQL database and so on. To accomplish this a Base class is present that has no adapter related code.
But there are Subclasses that modifying the Base code, that is, each adapter adds a method that creates its specific type of connection to
the Base class.

class Base
# Lots of non-adapter-related code removed...
end

class Base
  def self.mysql_connection(config)
 # Create and return a new MySQL connection, using
 # the user name, password, etc. stored in the
 # config hash...
  end
end

class Base
  def self.oracle_connection(config)
 # Create a new Oracle connection...
  end
end

If a structured object creation method like the Factory Method in a class is not implemented, we might end up creating methods for each new object we want to create.

References

[1] Wikipedia

[2] Programmers Heaven