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
1 Answer 1
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.
-
\$\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\$revliscano– revliscano2020年08月17日 16:12:33 +00:00Commented 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\$AJNeufeld– AJNeufeld2020年08月17日 16:43:31 +00:00Commented Aug 17, 2020 at 16:43
-
\$\begingroup\$ Invaluable information. This is the kind of clarification and inputs I was expecting to have. @AJNeufeld \$\endgroup\$revliscano– revliscano2020年08月17日 16:53:17 +00:00Commented Aug 17, 2020 at 16:53
Explore related questions
See similar questions with these tags.
super(FootballGoalKeeper, self)
can be replaced bysuper()
\$\endgroup\$