What is a Ruby factory method?

Why bother with factory methods?

(A) To simplify things:

  • Creating objects can be complicated, and

  • you may need to do this multiple times.

  • It's hard to remember:

    # ugh - too much work!
    driver = Person.new
    engine = Brrrm.new
    engine.turbo_charged = true
    engine.max_rpm = 100000    
    car = Porsche.new
    car.driver = driver
    car.engine = engine
    
    # preference - less to remember
    ben = PersonFactory.create("ben")
    car = PorscheFactory.create(ben)
    
    # and you get the following for free, without remembering:
    car.turbo_charged # => true
    car.engine # => brrrm
    car.driver # => ben_koshy
    car.driver.personality # => :excellent_dude
    
    # you can mix and match default values with options.
    # generally speaking you want to inject as much as you can
    # i.e. inverting dependencies. I make these illustrates to
    # explain a concept, not as an example of great coding.
    

(B) To allow for overridding / stubbing

If you are writing testable code, you might want to create your own specialised 'crash dummy vehicle' so you can test collisions etc. If you have a factory method / object, then you can do this easily. This is a somewhat adavanced topic - google "creating a seam" or "dependency injection" for more info.


A factory class is a clean way to have a single factory method that produces various kind of objects. It takes a parameter, a parameter that tells the method which kind of object to create. For example to generate an Employee or a Boss, depending on the symbol that is passed in:

class Person
  def initialize(attributes)
  end
end

class Boss
  def initialize(attributes)
  end
end

class Employee
  def initialize(attributes)
  end
end

class PersonFactory
  TYPES = {
    employee: Employee,
    boss: Boss
  }

  def self.for(type, attributes)
    (TYPES[type] || Person).new(attributes)
  end
end

and then:

employee = PersonFactory.for(:employee, name: 'Danny')
boss = PersonFactory.for(:boss, name: 'Danny')
person = PersonFactory.for(:foo, name: 'Danny')

I also wrote a more detailed blog post about that topic: The Factory Pattern


The Factory Method Pattern at least allows you to give an expressive name to what could otherwise be a complicated or opaque constructor. For instance if you have a constructor that takes a bunch of parameters, it may not be clear why to the caller, having a named Factory method or methods could potentially hide the complexity of the object creation and make your code more expressive of what is actually going on.

So in your case a bad design may be:

trainee = Person.new true

or

instructor = Person.new false

Where true or false branches to creating an instructor or trainee.

This could be improved by using a Factory method to clarify what is going on:

trainee = Person.create_trainee
instructor = Person.create_instructor