The Factory Method Pattern: Decoupling Object Creation
Master the Factory Method Pattern in Java. Learn how to loosen coupling in your code by letting subclasses decide which objects to instantiate.
Moshiour Rahman
Advertisement
The Problem: Tight Coupling
Imagine you are building a Logistics Management application. Initially, you only handle truck delivery.
public class Logistics {
public void planDelivery() {
Truck truck = new Truck(); // TIGHT COUPLING!
truck.deliver();
}
}
Great. But then your business grows. You need to handle Ships for overseas delivery.
The code is riddled with new Truck(). You have to find every instance and replace it with complex logic:
if (type.equals("SEA")) {
transport = new Ship();
} else {
transport = new Truck();
}
Your code is now fragile. Adding “Air” transport means modifying the core Logistics class again.
The Solution: The Factory Method
The Factory Method Pattern defines an interface for creating an object, but lets subclasses decide which class to instantiate. It lets a class defer instantiation to subclasses.
Real-Life Analogy: A Logistics Company 📦
- RoadLogistics: Knows how to create
Trucks. - SeaLogistics: Knows how to create
Ships.
The Client (you) just says “Plan Delivery”. You don’t care how the vehicle is created, you just know it will transport your goods.
Visualizing the Pattern

Implementation
1. The Product Interface
Common interface for all things this factory creates.
public interface Transport {
void deliver();
}
2. Concrete Products
public class Truck implements Transport {
@Override
public void deliver() {
System.out.println("Delivering by land in a box.");
}
}
public class Ship implements Transport {
@Override
public void deliver() {
System.out.println("Delivering by sea in a container.");
}
}
3. The Creator (Abstract Factory)
This is the core. It declares the factory method createTransport().
public abstract class Logistics {
// Core business logic uses the product, but doesn't create it directly
public void planDelivery() {
// CALL THE FACTORY METHOD
Transport transport = createTransport();
// Use the product
transport.deliver();
}
// THE FACTORY METHOD
public abstract Transport createTransport();
}
4. Concrete Creators
public class RoadLogistics extends Logistics {
@Override
public Transport createTransport() {
return new Truck();
}
}
public class SeaLogistics extends Logistics {
@Override
public Transport createTransport() {
return new Ship();
}
}
Usage
The client code works with the abstract type Logistics. It doesn’t care if it’s Road or Sea.
public class Application {
public static void main(String[] args) {
Logistics logistics;
// Configuration determines which factory to use
if (args[0].equals("sea")) {
logistics = new SeaLogistics();
} else {
logistics = new RoadLogistics();
}
// The application logic is decoupled from specific classes
logistics.planDelivery();
}
}
In The Wild (Real World Examples)
1. java.util.Calendar
When you call Calendar.getInstance(), it doesn’t just return a raw generic Calendar. Depending on your locale and timezone, it effectively acts like a factory returning:
GregorianCalendar(Western)BuddhistCalendar(Thai)JapaneseImperialCalendar(Japan)
2. Spring BeanFactory
The Spring Container is effectively a giant, sophisticated Factory. You ask for a bean (Product), and it handles the creation logic (scope, layout, dependencies).
Cheat Sheet
| Feature | Details |
|---|---|
| Category | Creational |
| Problem Solved | Framework code needs to create objects, but doesn’t know their concrete classes |
| Key implementation | abstract method createObject() |
| Pros | Single Responsibility Principle (Move creation code to one place), Open/Closed Principle (Add new types without breaking core logic) |
| Cons | Can lead to many subclasses (Parallel Class Hierarchies) |
Tips to Remember 🧠
- “Hire a Vendor”: Instead of building a car yourself (
new Car()), you hire a Factory (CarFactory). You tell them what you want, they deal with how to build it. - Frameworks: This is predominantly used in writing Frameworks/Libraries where you (the library author) need to let users (the developer) extend your components.
Advertisement
Moshiour Rahman
Software Architect & AI Engineer
Enterprise software architect with deep expertise in financial systems, distributed architecture, and AI-powered applications. Building large-scale systems at Fortune 500 companies. Specializing in LLM orchestration, multi-agent systems, and cloud-native solutions. I share battle-tested patterns from real enterprise projects.
Related Articles
The Builder Design Pattern: The Cure for Constructor Headache
Master the Builder Pattern in Java. Learn how to construct complex objects step-by-step, avoid telescoping constructors, and write readable code.
JavaThe Visitor Design Pattern: Add Operations Without Modifying Classes
Master the Visitor Pattern in Java. Learn how to add new operations to object structures using double dispatch.
JavaThe Strategy Design Pattern: Kill the If-Else Statements
Master the Strategy Pattern in Java. Learn how to replace complex if-else logic with interchangeable algorithms and follow the Open/Closed Principle.
Comments
Comments are powered by GitHub Discussions.
Configure Giscus at giscus.app to enable comments.