Abstract Factory Pattern in Python

I have been reading today about the Abstract Factory Pattern, and tried to make the following implementation.

I have seen a lot of implementations in the internet, where they use switch statements, but I must say that I didn't like that much, since the more factories you make, it seems to me that it makes very difficult to add new products, if needed.

Anyways, I was hoping you to take a look at it and let me know your opinions. Thanks in advance for taking your time to review it.

Factories

from abc import ABC, abstractmethod

class PlayerFactory(ABC):
"""
This class is meant to be an interface
"""
@abstractmethod
def create_goalkeeper(self):
pass

@abstractmethod
def create_defender(self):
pass

class FootballPlayerFactory(PlayerFactory):
def create_goalkeeper(self):
return FootballGoalkeeper()

def create_defender(self):
return FootballDefender()

class HockeyPlayerFactory(PlayerFactory):
def create_goalkeeper(self):
return HockeyGoalkeeper()

def create_defender(self):
return HockeyDefender()



Football players

class FootballPlayer:
def __init__(self, uses_hands):
self.uses_hands = uses_hands

def play(self):
print("I'm playing football!")

class FootballGoalkeeper(FootballPlayer):
def __init__(self):
super(FootballGoalkeeper, self).__init__(uses_hands=True)

class FootballDefender(FootballPlayer):
def __init__(self):
super(FootballDefender, self).__init__(uses_hands=False)


Hockey players (my creativity stopped here, so I didn't include any difference between goalkeepers and defenders)

class HockeyPlayer:
def play(self):
print("I'm playing hockey!")

class HockeyGoalkeeper(HockeyPlayer):
pass

class HockeyDefender(HockeyPlayer):
pass


• super(FootballGoalKeeper, self) can be replaced by super() Aug 17 '20 at 12:26
• Thanks! Oh yes, you're right. I'm just too used to that old syntax. Thanks for pointing that out. @hjpotter92 Aug 17 '20 at 14:38

As your code presently stands, you don't need the derived Factory classes. They don't do anything different from each other, so they can all be handled by a concrete base class.

class PlayerFactory:

def __init__(self, goal_keeper_class, defender_class):
self._goal_keeper_class = goal_keeper_class
self._defender_class = defender_class

def create_goalkeeper(self):
return self._goal_keeper_class()

def create_defender(self):
return self._defender_class()

player_factory = {
"Football": PlayerFactory(FootballGoalkeeper, FootballDefender),
"Hockey": PlayerFactory(HockeyGoalkeeper, HockeyDefender),
}


Example Usage:

>>> player = player_factory["Hockey"].create_defender()
>>> type(player)
<class '__main__.HockeyDefender'>
>>> player.play()
I'm playing hockey!
>>>


If there is some aspect of the factories which actually do something different, and thus necessitate separated derived classes, you'll need to include that in your question.

• Thank you for this, it's very useful. Hmm yes, your code makes so much more sense, but I was just trying to think in a way to use or make an example of Abstract Factory pattern. :-( I guess I'm still confused by the use cases of this pattern. Aug 17 '20 at 16:12
• Well, if you added a "create_team" method, your various factories might return different numbers of players for the various positions. You could implement it with code in different derived classes, but it could be simply data-driven without needing derived classes. There is always more than one way to do it. The Abstract Factory pattern is a useful tool for your toolbox, but it isn't necessarily the right tool to use until your problem becomes significantly more complex. Aug 17 '20 at 16:43
• Invaluable information. This is the kind of clarification and inputs I was expecting to have. @AJNeufeld Aug 17 '20 at 16:53