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). The pattern focuses on creating some object from some family of objects (i.e. those that implement the same interface or extend a certain base class). Moreover, it assumes the existence of an interface or an abstract class that will be responsible for creating such objects.

In the following example, the object family represents the Game interface and its two implementations - PCGame and BoardGame. GameFactory is a common interface for creating objects of type Game. There are two implementations that create a complex object with a simple method call:

factory_method

package pl.sdacademy.factorymethod;

public interface Game {
  String getName();
  String getType();
  int getMinNumberOfPlayers();
  int getMaxNumberOfPlayers();
  boolean canBePlayedRemotely();
}
package pl.sdacademy.factorymethod;

public class BoardGame implements Game {

  private String name;
  private String type;
  private int maxPlayersNum;

  public BoardGame(final String name, final String type, final int maxPlayersNum) {
    this.name = name;
    this.type = type;
    this.maxPlayersNum = maxPlayersNum;
  }

  @Override
  public String getName() {
    return name;
  }

  @Override
  public String getType() {
    return type;
  }

  @Override
  public int getMinNumberOfPlayers() {
    return 2;
  }

  @Override
  public int getMaxNumberOfPlayers() {
    return maxPlayersNum;
  }

  @Override
  public boolean canBePlayedRemotely() {
    return false;
  }

  @Override
  public String toString() {
    return "BoardGame{" +
        "name='" + name + '\'' +
        ", type='" + type + '\'' +
        ", maxPlayersNum=" + maxPlayersNum +
        '}';
  }
}
package pl.sdacademy.factorymethod;

public class PCGame implements Game {

  private final String name;
  private final String type;
  private final int minNumberOfPlayers;
  private final int maxNumberOfPlayers;
  private final boolean isOnline;

  public PCGame(final String name, final String type, final int minNumberOfPlayers, final int maxNumberOfPlayers, final boolean isOnline) {
    this.name = name;
    this.type = type;
    this.minNumberOfPlayers = minNumberOfPlayers;
    this.maxNumberOfPlayers = maxNumberOfPlayers;
    this.isOnline = isOnline;
  }

  @Override
  public String getName() {
    return name;
  }

  @Override
  public String getType() {
    return type;
  }

  @Override
  public int getMinNumberOfPlayers() {
    return minNumberOfPlayers;
  }

  @Override
  public int getMaxNumberOfPlayers() {
    return maxNumberOfPlayers;
  }

  @Override
  public boolean canBePlayedRemotely() {
    return isOnline;
  }

  @Override
  public String toString() {
    return "PCGame{" +
        "name='" + name + '\'' +
        ", type='" + type + '\'' +
        ", minNumberOfPlayers=" + minNumberOfPlayers +
        ", maxNumberOfPlayers=" + maxNumberOfPlayers +
        ", isOnline=" + isOnline +
        '}';
  }
}
package pl.sdacademy.factorymethod;

public interface GameFactory {
  Game create();
}
package pl.sdacademy.factorymethod;

public class MonopolyGameCreator implements GameFactory {
  @Override
  public Game create() {
    return new BoardGame("Monopoly", "Family Game", 4);
  }
}
package pl.sdacademy.factorymethod;

public class ValorantGameCreator implements GameFactory {
  @Override
  public Game create() {
    return new PCGame("Valorant", "FPS", 4, 10, true);
  }
}
package pl.sdacademy.factorymethod;

public class FactoryMethodUsage {
  public static void main(String[] args) {
    final String type = args[0];
    GameFactory gameFactory;
    if (type.equals("PC")) {
      gameFactory = new ValorantGameCreator();
    } else if (type.equals("Board")){
      gameFactory = new MonopolyGameCreator();
    } else {
      throw new RuntimeException("unknown game type");
    }

    Game createdGame = gameFactory.create();
    System.out.println("Created game " + createdGame);
  }
}

To sum up, we use the Factory Method pattern when we frequently want to create an object from a certain family (which is potentially complicated, i.e. it 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 SOLID principle but can potentially consist of many classes.