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:
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.