Skip to main content

Factory Design Pattern

Problem​

You: Hey Shubh, I've heard about the Factory Design Pattern. Can you explain what problem it solves?

Shubh: Sure! Let's consider a scenario where we have a Vehicle interface and two classes, Car and Bike, that implement this interface. The client code wants to create objects of Car.

You: We can easily do something like Vehicle vehicle = new Car();.

Shubh: Yes, but there's a problem with that approach. If you do it this way, your code becomes tightly coupled. This means if you want to change the object from Car to Bike in the future, you'll have to update your code everywhere you've instantiated the Car. And if there are multiple client codes, the problem multiplies.

You: I see. So the issue is that the client code directly depends on the concrete classes. How do we solve that?

Main.java
public interface Vehicle {
void drive();
}

public class Car implements Vehicle {
@Override
public void drive() {
System.out.println("We are driving a car");
}
}

public class Bike implements Vehicle {
@Override
public void drive() {
System.out.println("We are driving a bike");
}
}

// Client code
public class Main {
public static void main(String[] args) {
Vehicle vehicle = new Car(); // Tight coupling
vehicle.drive();
}
}

You: So here, if I need to change from Car to Bike, I'd have to change the client code, right?

UML​

Shubh: Right! Now let's introduce the Factory Design Pattern to handle this.

Shubh: The idea is to separate the object creation logic from the client code. Let me show you how.

UML for Factory Design Pattern

UML for Factory Design Pattern

Shubh: Now, whenever the client wants a Bike or a Car, they just ask the VehicleFactory. The factory takes care of creating the appropriate object.

You: So if I want to add a new vehicle type, like a Bus, I just need to update the factory and add a new class for Bus. I don't need to change the client code at all.

Shubh: Exactly! This is called loose coupling. The client code is not directly dependent on the concrete classes. It only interacts with the factory to get the objects it needs.

You: That makes sense. It really simplifies the code maintenance and future enhancements.

Shubh: Right! And it makes your code more flexible and easier to manage. This is the essence of the Factory Design Pattern.

You: Thanks for explaining, Shubh. I understand how the Factory Design Pattern solves the problem of tight coupling and makes the code more maintainable.

Code​

Defining the Vehicle Interface and Concrete Classes​

Vehicle.java
public interface Vehicle {
void drive();
}
Bike.java
public class Bike implements Vehicle {
@Override
public void drive() {
System.out.println("We are driving a bike");
}
}
Car.java
public class Car implements Vehicle {
@Override
public void drive() {
System.out.println("We are driving a car");
}
}

Enum for Vehicle Types​

VehicleType.java
public enum VehicleType {
CAR, BIKE, BUS;
}

Implementing the Factory Class​

VehicleFactory.java
public class VehicleFactory {
static Vehicle getVehicle(String vehicleName) throws Exception {
switch (VehicleType.valueOf(vehicleName)) {
case CAR:
return new Car();
case BIKE:
return new Bike();
case BUS:
return new Bus();
default:
throw new Exception("No such vehicle available");
}
}
}

Client Code Using the Factory​

Main.java
import java.util.Scanner;

public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("Mention the type of the vehicle");
String vehicleName = input.nextLine().toUpperCase();

try {
Vehicle myVehicle = VehicleFactory.getVehicle(vehicleName);
myVehicle.drive();
} catch (Exception e) {
System.out.println("Invalid vehicle type: " + vehicleName);
}
}
}

Key Benefits of Using the Factory Design Pattern​

Before watching, make sure you give it a try
  • Loose Coupling: The client code is not tightly coupled with the concrete classes (Car, Bike, etc.). It only knows about the Vehicle interface and interacts with the VehicleFactory to get the desired object.

  • Scalability: Adding a new type of vehicle, like Bus, only requires updating the factory method and adding a new class. The client code remains unchanged.

  • Maintainability: It becomes easier to manage and modify the code as changes are localized to the factory class. This reduces the risk of bugs and makes the codebase more maintainable.

  • Flexibility: The factory can return different implementations based on input or configuration, allowing for more dynamic and flexible object creation.