What is a Ruby factory method?
Asked Answered
F

3

13

I understand that a factory method is a class method that utilises the self keyword and instantiates an object of it's own class. I don't understand how this is useful or how it can extend the functionality of initialize method.

I'm working on a project creating a command line address book that asks me to use a factory pattern on the Person class so that I can create a Trainee or Instructor (subclasses) with different attributes.

Furrier answered 21/5, 2016 at 14:54 Comment(1)
@JörgWMittag so initialize methods are not constructors? If not then how would you define them?Furrier
F
24

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

Flooring answered 13/1, 2017 at 20:29 Comment(0)
S
4

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
Sonja answered 21/5, 2016 at 16:52 Comment(1)
Are you saying that the primary purpose of the factory method is not to extend the functionality of the object creation process, but to make your code more less complicated and more readable?Furrier
D
1

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:

    driver = Person.new
    engine = Brrrm.new
    engine.turbo_charged = true
    engine.max_rpm = 100000    
    car = Porsche.new
    car.driver = driver
    car.engine = engine
    # ugh - too much work!
    

Let's simply it to this:

  ben = PersonFactory.create(name: "ben")
  car = PorscheFactory.create(driver: ben)
  # two lines, and nothing more

  # and you get the following for free: 
  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.

Delafuente answered 4/10, 2021 at 1:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.