Factory Method Design Pattern
In the previous post of this Design series, we learned about the Singleton Design Pattern - What is it? How to use it? When to use it?
In this post, let's look at another Creational Design pattern - Factory Method Design Pattern.
Introduction
Problem Statement
Before we look at the implementation of this pattern, first we need to understand the utility of this pattern and what kind of problem are we trying to solve?
Imagine you are owner of Tesla (Bye Elon!). When you cofounded the company, you decided to create only cars. Hence your code only has one Car class where you are maintaining all the attributes and methods.
However, one day you have decided to manufacture the Tesla Pickup Truck. Now what you will do? Create another Truck class and try to make it work along with the Car class. But what if tomorrow, you wish to add a Tesla Bike or a Airplane and so on and so forth. Soon your code will become a pile of mess! which changes behaviour based on the vehicle type.
This is where the Factory Method pattern comes into picture.
Factory Method Pattern to Rescue
The Factory method pattern allows us to replace the direct class instantiation with a "Factory" which returns back us the object as per our needs. This objects are often know as "products" of the factory.
Components of Factory Design Pattern
- Factory Interface - Implemented by the different Product Factories.
- Factory Concrete Classes - Implement the Factory Interface and contain the respective Product Instantiation Logic based on certain conditions.
- Product Interface - Implemented by the product concrete classes.
- Product Concrete Classes - Concrete implementation of the product classes. These are used by the Concrete Factory Classes to return the respective product object.
Implementation
Let's take the previous example to discuss the implementation -
Product Interface - Vehicle.java
package factoryDesign;
public interface Vehicle {
void move();
void turn();
}
Product Concrete Classes
Car.java
package factoryDesign;
public class Car implements Vehicle {
public Car() {
System.out.println("Hi! I am a car!");
}
public void move() {
System.out.println("Car Moves");
}
public void turn() {
System.out.println("Car Turns");
}
}
Truck.java
package factoryDesign;
public class Truck implements Vehicle {
public Truck() {
System.out.println("Hi! I am a Truck!");
}
public void move() {
System.out.println("Truck Moves");
}
public void turn() {
System.out.println("Truck Turns");
}
}
Factory Interface - VehicleFactory.java
package factoryDesign;
import Vehicle;
public interface VehicleFactory {
public Vehicle getVehicle(String vehType);
}
Factory Concrete Classes
CarFactory.java
package factoryDesign;
import Vehicle;
public class CarFactory implements VehicleFactory {
public Vehicle getVehicle(String vehType) {
Vehicle vehicle = new Car();
return vehicle;
}
}
TruckFactory.java
package factoryDesign;
import Vehicle;
public class TruckFactory implements VehicleFactory {
public Vehicle getVehicle(String vehType) {
Vehicle vehicle = new Truck();
return vehicle;
}
}
Usability
- Use the Factory Method when you don’t know beforehand the exact types and dependencies of the objects your code should work with.
- Use the Factory Method when you want to provide users of your library or framework with a way to extend its internal components.
- Use the Factory Method when you want to save system resources by reusing existing objects instead of rebuilding them each time.