The Factory Method pattern provides a way for creating objects without specifying the concrete type of them.
Factory Method defines a method for creating objects, which is overridden by subclasses. The subclasses decide which type of objects get instantiated.
Factory Method is a creational pattern.
Factory Method relies on inheritance (incl. interface implementation). It delegates the object creation to subclasses.
Abstract Factory relies on object composition. It delegates the object creation to another object.
The Factory Method is a method that can be overridden by subclasses. Abstract Factory is an object that has multiple factory methods.
Both patterns encapsulate and hide the object creation logic. The type of the created objects are determined at run-time.
In the next Java example, we are going to instantiate different types of cars. For now a car can be a petrol car or an electric car, and both of them can be real or cartoon.
The abstract Car
class is the base class of all cars.
It has four fields, which get values by the subclasses.
The subclasses also override its abstract create
method.
package com.programcodex.designpatterns.factorymethod;
public abstract class Car {
protected String carType;
protected String engine;
protected String energyStorage;
protected String gearbox;
public abstract void create();
@Override
public String toString() {
StringBuilder sb = new StringBuilder("\n### ");
sb.append(carType).append(" car ###")
.append("\nEngine: ").append(engine);
if (energyStorage != null) {
sb.append("\nEnergy storage: ").append(energyStorage);
}
if (gearbox != null) {
sb.append("\nGearbox: ").append(gearbox);
}
return sb.toString();
}
}
The PetrolCar
class extends the Car
class and represents a real petrol car.
In the create
method it gives values to the four fields, which are defined in the base class.
package com.programcodex.designpatterns.factorymethod;
public class PetrolCar extends Car {
@Override
public void create() {
carType = "Petrol";
engine = "Petrol engine";
energyStorage = "Fuel tank";
gearbox = "Automatic";
}
}
The ElectricCar
class also extends the Car
class and represents a real electric car.
In the create
method, it gives values to the fields, which are defined in the base class,
but this class doesn’t provide value for the gearbox field because electric cars don’t have gearboxes.
package com.programcodex.designpatterns.factorymethod;
public class ElectricCar extends Car {
@Override
public void create() {
carType = "Electric";
engine = "Electric motor";
energyStorage = "Battery";
}
}
Now come the cartoon versions of the cars.
Obviously, cartoon cars are much simpler than real ones, so they have less fields.
The CartoonPetrolCar
only uses two fields in the create
method.
package com.programcodex.designpatterns.factorymethod;
public class CartoonPetrolCar extends Car {
@Override
public void create() {
carType = "Cartoon Petrol";
engine = "Petrol engine";
}
}
Just like the previous class, the CartoonElectricCar
class gives values only to two fields.
package com.programcodex.designpatterns.factorymethod;
public class CartoonElectricCar extends Car {
@Override
public void create() {
carType = "Cartoon Electric";
engine = "Electric motor";
}
}
Now we have a lot of car objects. Next we need factories to instantiate the appropriate ones.
The Factory
interface defines the signature of factory method.
package com.programcodex.designpatterns.factorymethod;
public interface Factory {
public Car createCar(String type);
}
There will be two factory classes. One of them is responsible for creating real cars, the other is responsible for creating cartoon cars.
The CarFactory
class implements the Factory
interface and produces real cars.
The createCar
method has a type
parameter.
The type
can be petrol
or electric
.
This method hides the object creation logic.
It instantiates a kind of Car
and calls its create
method.
After that, the new object is returned to the caller, who doesn’t know the exact type of the object.
It only knows it’s a kind of Car
. So in Factory Method pattern the objects are loosely coupled.
package com.programcodex.designpatterns.factorymethod;
public class CarFactory implements Factory {
@Override
public Car createCar(String type) {
Car car = null;
if ("petrol".equals(type)) {
car = new PetrolCar();
} else if ("electric".equals(type)) {
car = new ElectricCar();
}
car.create();
return car;
}
}
The CartoonCarFactory
class is almost the same as the CarFactory
class,
but this one instantiates cartoon cars.
package com.programcodex.designpatterns.factorymethod;
public class CartoonCarFactory implements Factory {
@Override
public Car createCar(String type) {
Car car = null;
if ("petrol".equals(type)) {
car = new CartoonPetrolCar();
} else if ("electric".equals(type)) {
car = new CartoonElectricCar();
}
car.create();
return car;
}
}
And we are done. It’s time to run these things.
The createCars
method receives a Factory
instance as an argument,
which can be CarFactory
or CartoonCarFactory
.
It doesn’t know the exact type of the factory, but with the help of it,
it creates a petrol
and an electric
car.
From the main
method, the createCars
method is called twice.
Once with a CarFactory
instantiate and once with a CartoonCarFactory
instance.
package com.programcodex.designpatterns.factorymethod;
public class TestFactoryMethod {
public static void main(String[] args) {
Factory factory;
factory = new CarFactory();
createCars(factory);
factory = new CartoonCarFactory();
createCars(factory);
}
private static void createCars(Factory factory) {
Car car = factory.createCar("petrol");
System.out.println(car);
car = factory.createCar("electric");
System.out.println(car);
}
}
The output of the above test class: