Padrão Abstrato de Fábrica em Python

Aug 17 2020

Estive lendo hoje sobre o Abstract Factory Pattern e tentei fazer a seguinte implementação.

Já vi muitas implementações na internet, onde usam switchdeclarações, mas devo dizer que não gostei muito, pois quanto mais fábricas você faz, me parece que dificulta muito a adição de novos produtos, se necessário.

De qualquer forma, eu estava esperando que você desse uma olhada e me desse sua opinião. Agradecemos antecipadamente por dedicar seu tempo para revisá-lo.

Fábricas

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()

Jogadores de futebol

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)

Jogadores de hóquei ( minha criatividade parou aqui, então não incluí nenhuma diferença entre goleiros e zagueiros )

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


class HockeyGoalkeeper(HockeyPlayer):
    pass


class HockeyDefender(HockeyPlayer):
    pass

Respostas

2 AJNeufeld Aug 17 2020 at 22:24

Como seu código está atualmente, você não precisa das classes Factory derivadas. Eles não fazem nada diferente um do outro, então todos podem ser tratados por uma classe base concreta.

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),
}

Exemplo de uso:

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

Se houver algum aspecto das fábricas que realmente fazem algo diferente e, portanto, necessitam de classes derivadas separadas, você precisará incluir isso em sua pergunta.