April 19, 2017
The Factory Pattern and Circular Dependencies
Say I’m writing the code for a treat dispenser for my pets. In the simplest sense, this would look like this:
pet = recognize_pet() treat = pet.treat() dispense(treat)
To be able to implement the
pet.treat() method, I need to first know which pet
it is. If I were to follow a polymorphic, object oriented, duck-typed1
approach, I would need
recognize_pet() to return an object that responds to
but I wouldn’t really care what the return type was.
Say I decided to make
recognize_pet() smart and return an object based on the sounds
it heard nearby. For example, if it heard a meow, it would return a
Cat() instance which
would response appropriately to
Let’s look at
def recognize_pet(): sound = mic_input() if sound = 'woof': Dog() elif sound == 'meow': Cat() elif sound == 'trumpet': Horse()
mic_input() for this post.
This code is kind of procedural and I’ve just learned about the Factory Pattern. I’d like to write something like this:
def recognize_pet(): sound = mic_input() return Animal.from_sound(sound)
But I still want to return instances of
Horse, so they
can each respond to
Here’s how I might define these classes:
class Animal(): @classmethod def from_sound(cls, sound): if sound == 'woof': return Dog() elif sound == 'meow': return Cat() elif sound == 'horse': return Horse() def treat(self): raise 'implement me in subclass' class Cat(Animal): def treat(self): return 'cat candy' class Dog(Animal): def treat(self): return 'dog candy'
Ok, so we haven’t really gotten rid of our procedural code, but at least we’ve contained it –we can pull out this mapping into a data file or even an in-memory map later.
Let me get to the point2.
I typically prefer having one class per file in my projects, so this is how I would try to organize this code:
from animal.cat import Cat from animal.dog import Dog class Animal(): @classmethod def from_sound(sound) # omitted, see above # returns an instance of something that inherits from Animal
from animal import Animal class Cat(Animal): # omitted
from animal import Animal class Dog(Animal): # omitted
and so on for each animal type…
Here’s the problem…
This creates a circular dependency making this pattern kind of annoying to use.
The problem, is that importing a class from a module means evaluating the whole file. So any imports will also be evaluated. One solution is to move an import in a place that won’t be evaluated when the module is loaded; i.e. inside a method.
class Animal(): @classmethod def from_sound(cls, sound): if sound == 'woof': from animal.dog import Dog return Dog() elif sound == 'meow': from animal.cat import Cat return Cat() elif sound == 'horse': from animal.horse import Horse return Horse()
This is the only decent solution I’ve found for this problem.
For what it’s worth, I’m seeing this problem in Ruby also, and I can’t imagine it would be different in other environments.
- Could I duck-type a treat for a duck if I had one?
- I really got carried away with the whole pet-feeding use-case for the factory pattern there…