Patrón de fábrica abstracto en Python

Aug 17 2020

He estado leyendo hoy sobre Abstract Factory Pattern e intenté hacer la siguiente implementación.

He visto muchas implementaciones en internet, donde usan switchsentencias, pero debo decir que no me gustó mucho, ya que entre más fábricas haces, me parece que se hace muy difícil agregar nuevos productos, si es necesario.

De todos modos, esperaba que le echaras un vistazo y me dieras tu opinión. Gracias de antemano por tomarse su tiempo para revisarlo.

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

Jugadores de futbol

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)

Jugadores de hockey ( mi creatividad se detuvo aquí, así que no incluí ninguna diferencia entre porteros y defensores )

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


class HockeyGoalkeeper(HockeyPlayer):
    pass


class HockeyDefender(HockeyPlayer):
    pass

Respuestas

2 AJNeufeld Aug 17 2020 at 22:24

Tal como está su código actualmente, no necesita las clases Factory derivadas. No hacen nada diferente entre sí, por lo que todos pueden ser manejados por una clase 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),
}

Ejemplo de uso:

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

Si hay algún aspecto de las fábricas que realmente hace algo diferente y, por lo tanto, necesita clases derivadas separadas, deberá incluirlo en su pregunta.