Factory pattern
From wikinotes
A class/method responsible for choosing/instantiating a class for you.
Basics
Given classes
Cat, Dog
that implement interfaceAnimal
,
We want a factory that chooses the desired pet.module Animal interface! sig { abstract.returns(String) } def speak; end end class Cat include Animal sig { override.returns(String) } def speak "meow" end end class Dog include Animal sig { override.returns(String) } def speak "woof" end endclass PetFactory def from(interests) return Cat.new if interests.include?(:homebody) Dog.new end end
Registering Concretions
Subclass Hooks
NOTE:
careful with evaluation order. If these hooks are evaluated lazily, your register will be empty (ex. ruby/python)
If your language supports subclass hooks, even without eager loading you can register concretions automatically.
reusing the previous example:
class AnimalBase # when inheritance is read, is registered with the superclass's '@register' def self.inherited(concretion) register(concretion) end def self.register(concretion) @register << concretion end def self.from(interests) @register.find { |concretion| concretion.handles?(interests) } end endclass Cat < AnimalBase include Animal def speak "meow" end def self.handles?(interests) interests.include?(:homebody) end end class Dog < AnimalBase include Animal def speak "woof" end def self.handles?(interests) !interests.include?(:homebody) end endclass AnimalBase def self.from(interests) AnimalBase.from(interests) end endOrdered Array
Otherwise you can keep an array classes, and pass through it to determine the class to choose
class PetFactory def self.from(interests) [Cat, Dog].find { |animal| animal.handles?(interests) }.new end end