3
\$\begingroup\$

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
asked Aug 17, 2020 at 0:56
\$\endgroup\$
2
  • 2
    \$\begingroup\$ super(FootballGoalKeeper, self) can be replaced by super() \$\endgroup\$ Commented Aug 17, 2020 at 12:26
  • \$\begingroup\$ Thanks! Oh yes, you're right. I'm just too used to that old syntax. Thanks for pointing that out. @hjpotter92 \$\endgroup\$ Commented Aug 17, 2020 at 14:38

1 Answer 1

2
\$\begingroup\$

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.

answered Aug 17, 2020 at 15:24
\$\endgroup\$
3
  • \$\begingroup\$ 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. \$\endgroup\$ Commented Aug 17, 2020 at 16:12
  • 2
    \$\begingroup\$ 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. \$\endgroup\$ Commented Aug 17, 2020 at 16:43
  • \$\begingroup\$ Invaluable information. This is the kind of clarification and inputs I was expecting to have. @AJNeufeld \$\endgroup\$ Commented Aug 17, 2020 at 16:53

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.