DEV Community

Cover image for Factory Design Pattern in Java (With Real-Time Example)
Aswin Arya
Aswin Arya

Posted on

Factory Design Pattern in Java (With Real-Time Example)

Introduction

In real-world applications, creating objects directly using new can tightly couple your code, making it hard to scale and maintain. As projects grow, this leads to messy conditionals, duplication, and poor flexibility.

The Factory Design Pattern solves this by centralizing object creation logic—allowing you to create objects without exposing instantiation details to the client.


What is Factory Design Pattern?

The Factory Design Pattern is a creational design pattern that provides an interface for creating objects, but lets subclasses decide which class to instantiate.

In simple words:
👉 “Instead of creating objects directly, you ask a factory to create them for you.”


Why Do We Need Factory Pattern?

In my decade of teaching Java, I’ve seen developers struggle with:

  • Tight coupling between classes
  • Repeated object creation logic
  • Difficulty in adding new features

Factory Pattern solves:

  • Loose coupling
  • Centralized object creation
  • Easy scalability

Real-Time Scenario

Our students in Hyderabad often relate to this example:

🚗 Vehicle Manufacturing System

Imagine you are building a system for a vehicle company.

You have multiple vehicle types:

  • Car
  • Bike
  • Truck

Instead of creating objects like:

Vehicle v = new Car();
Enter fullscreen mode Exit fullscreen mode

You use a factory:

Vehicle v = VehicleFactory.getVehicle("CAR");
Enter fullscreen mode Exit fullscreen mode

Step-by-Step Implementation

Step 1: Create an Interface

public interface Vehicle {
    void drive();
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Create Concrete Classes

public class Car implements Vehicle {
    public void drive() {
        System.out.println("Driving Car");
    }
}
Enter fullscreen mode Exit fullscreen mode
public class Bike implements Vehicle {
    public void drive() {
        System.out.println("Riding Bike");
    }
}
Enter fullscreen mode Exit fullscreen mode
public class Truck implements Vehicle {
    public void drive() {
        System.out.println("Driving Truck");
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Create Factory Class

public class VehicleFactory {

    public static Vehicle getVehicle(String type) {

        if (type == null) return null;

        switch (type.toUpperCase()) {
            case "CAR":
                return new Car();
            case "BIKE":
                return new Bike();
            case "TRUCK":
                return new Truck();
            default:
                throw new IllegalArgumentException("Invalid vehicle type");
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Client Code

public class Main {
    public static void main(String[] args) {

        Vehicle v1 = VehicleFactory.getVehicle("CAR");
        v1.drive();

        Vehicle v2 = VehicleFactory.getVehicle("BIKE");
        v2.drive();
    }
}
Enter fullscreen mode Exit fullscreen mode

Expert Explanation

In my experience building enterprise apps:

  • The client doesn’t know which class is instantiated
  • Object creation logic is encapsulated in one place
  • Easy to extend without modifying client code

Edge Cases You Must Handle

❗ 1. Invalid Input

VehicleFactory.getVehicle("PLANE"); // Exception
Enter fullscreen mode Exit fullscreen mode

✔ Always validate input and throw meaningful exceptions


❗ 2. Null Values

VehicleFactory.getVehicle(null);
Enter fullscreen mode Exit fullscreen mode

✔ Handle nulls to avoid NullPointerException


❗ 3. Too Many Conditions

If you add many types:

if-else or switch becomes messy
Enter fullscreen mode Exit fullscreen mode

✔ Solution: Use Map or Reflection-based factory


Improved Factory Using Map

import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;

public class BetterVehicleFactory {

    private static final Map<String, Supplier<Vehicle>> registry = new HashMap<>();

    static {
        registry.put("CAR", Car::new);
        registry.put("BIKE", Bike::new);
        registry.put("TRUCK", Truck::new);
    }

    public static Vehicle getVehicle(String type) {
        Supplier<Vehicle> supplier = registry.get(type.toUpperCase());
        if (supplier != null) {
            return supplier.get();
        }
        throw new IllegalArgumentException("Invalid vehicle type");
    }
}
Enter fullscreen mode Exit fullscreen mode

Key Advantages

  • Loose coupling
  • Better code readability
  • Easy to add new classes
  • Follows Open/Closed Principle

Disadvantages

  • Adds extra classes
  • Can increase complexity for small apps

Factory vs Singleton (Quick Comparison)

Feature Factory Pattern Singleton Pattern
Purpose Object creation Single instance
Flexibility High Low
Usage Multiple objects One object only
Example VehicleFactory Logger instance

Where Factory Pattern is Used in Real Projects

  • Spring Framework (BeanFactory, ApplicationContext)
  • Logging frameworks
  • Payment gateway integrations
  • Notification systems (Email, SMS, Push)

When to Use Factory Pattern

Use it when:

  • You don’t know exact object type at runtime
  • You want to centralize object creation
  • You need to follow clean architecture

When NOT to Use

Avoid when:

  • Object creation is simple
  • Only one class is needed
  • Over-engineering small applications

Quick FAQ

1. What is Factory Pattern in simple terms?

It creates objects without exposing instantiation logic.

2. Is Factory Pattern used in Spring?

Yes, Spring internally uses Factory patterns for bean creation.

3. What is the difference between Factory and Abstract Factory?

Factory creates one product, Abstract Factory creates families of related objects.

4. Is Factory Pattern thread-safe?

Depends on implementation.

5. Can Factory Pattern replace Singleton?

No, both serve different purposes.


Final Thoughts

The Factory Design Pattern is one of the most practical patterns you’ll use in real-world Java development. It improves flexibility, scalability, and maintainability.

If you want to master design patterns with real-time scenarios and crack interviews confidently, I recommend exploring:
https://www.ashokit.in/courses/core-java-online-training

Follow the complete roadmap to become a Java Full Stack Developer:
https://www.ashokit.in/java-full-stack-developer-roadmap

Top comments (0)