Skip to content

Factory Method

The Factory Method design pattern is used to create a potentially complex object based on some property (for example, name or type). It focus on creating an object from a certain family of objects (those that implement the same interface or extend one base class). In addition, it assumes the existence of an interface or abstract class that will be responsible for creating such objects.

In the example below, the object family represents the Game interface and its two implementations - PCGame and BoardGame. A common interface for creating objects of type Game is GameFactory. There are two implementations that create a complex object by simply calling the method:

factory_method

class Game:
    def get_name(self):
        pass

    def get_type(self):
        pass

    def get_min_number_of_players(self):
        pass

    def get_max_number_of_players(self):
        pass

    def can_be_played_remotely(self):
        pass
class BoardGame(Game):
    def __init__(self, name, type, max_player_num):
        self._name = name
        self._type = type
        self._max_player_num = max_player_num

    def get_name(self):
        return self._name

    def get_type(self):
        return self._type

    def get_min_number_of_players(self):
        return 2

    def get_max_number_of_players(self):
        return self._max_player_num

    def can_be_played_remotely(self):
        return False

    def __str__(self):
        return f"{__name__} [name='{self._name}', type='{self._type}', max_player_num={self._max_player_num}]"
class PCGame(Game):
    def __init__(self, name, type, min_player_num, max_player_num, is_online):
        self._name = name
        self._type = type
        self._min_player_num = min_player_num
        self._max_player_num = max_player_num
        self._is_online = is_online

    def get_name(self):
        return self._name

    def get_type(self):
        return self._type

    def get_min_number_of_players(self):
        return self._min_player_num

    def get_max_number_of_players(self):
        return self._max_player_num

    def can_be_played_remotely(self):
        return False

    def __str__(self):
        return (f"{__name__} [name='{self._name}', type='{self._type}', min_player_num={self._min_player_num}"
                f", max_player_num={self._max_player_num}, is_online={self._is_online}]")
class GameFactory:
    def create(self):
        pass
class MonopolyGameCreator(GameFactory):
    def create(self):
        return BoardGame("Monopoly", "Family Game", 4)
class ValorantGameCreator(GameFactory):
    def create(self):
        return PCGame("Valorant", "FPS", 4, 10, True)
def main():
    game_type = input('Enter the type of game [PC, Board]: ')
    game_factory = None
    if game_type == 'PC':
        game_factory = ValorantGameCreator()
    elif game_type == 'Board':
        game_factory = MonopolyGameCreator()

    if game_factory:
        game = game_factory.create()
        print(game)


if __name__ == '__main__':
    main()

We use the Factory Method pattern when we repeatedly want to create an object from a certain family (which is potentially complicated, i.e. consists of many fields or is difficult to construct). It also allows us to hide the details of the structure of a given object, irrelevant from the user's perspective. This pattern follows the rules SOLID but it can potentially consist many classes.