Picture of Mehul Kar

Mehul Kar

Link to Twitter profile Link to email Link to RSS feed

Apr 19, 2017

The Factory Pattern and Circular Dependencies

programming python

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 .treat(), 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 treat().

Let's look at recognize_pet() then:

def recognize_pet():
sound = mic_input()
if sound = 'woof':
Dog()
elif sound == 'meow':
Cat()
elif sound == 'trumpet':
Horse()

Let's ignore 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 Cat and Dog and Horse, so they can each respond to treat() differently.

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:

  1. in animal/__init__.py

    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
  2. In animal/cat.py

    from animal import Animal
    class Cat(Animal):
    # omitted
  3. In animal/dog.py

    from animal import Animal
    class Dog(Animal):
    # omitted
  4. and so on for each animal type...

Here's the problem... animal/__init__.py imports Cat from animal/cat.py, and animal/cat.py imports Animal from animal/__init__.py.

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.

Footnotes

  1. Could I duck-type a treat for a duck if I had one?
  2. I really got carried away with the whole pet-feeding use-case for the factory pattern there...

Want to talk about this post? Email me or send me a toot @mehulkar.