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