DEV Community

Priyank Bhardwaj
Priyank Bhardwaj

Posted on

Factory Method Design Pattern

🏭 Factory Method Design Pattern in Java

The Factory Method Pattern is one of the most commonly used creational design patterns. It provides a way to delegate the instantiation logic to subclasses, promoting loose coupling and scalability.


πŸ’‘ What is the Factory Method Pattern?

"Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses." β€” Gang of Four

It’s like giving the blueprint of object creation to a class but leaving the actual object-making to child classes.


🧠 Real-World Analogy

Imagine a Logistics company. Depending on the terrain, you may want to deliver using a Truck or a Ship. The decision is made at runtime, based on client needs.

Each Logistics center (subclass) decides how to deliver:

  • RoadLogistics β†’ creates a Truck
  • SeaLogistics β†’ creates a Ship

Use Case Overview

We are building a logistics management system that delivers items either by truck (land) or ship (sea). But the main client (application) doesn't know which transport will be used β€” it just asks logistics to "plan delivery".

1. Product Interface β€” Transport.java


public interface Transport {
    void deliver();
}

Enter fullscreen mode Exit fullscreen mode

This is the common interface for all types of transport. Each transport will define its own way to deliver().

2. Concrete Products β€” Truck.java and Ship.java


public class Truck implements Transport {
    @Override
    public void deliver() {
        System.out.println("Deliver by land in a box.");
    }
}

Enter fullscreen mode Exit fullscreen mode

public class Ship implements Transport {
    @Override
    public void deliver() {
        System.out.println("Deliver by sea in a container.");
    }
}

Enter fullscreen mode Exit fullscreen mode

Each class implements the Transport interface and defines how the delivery happens.

3. Creator Class (Factory) β€” Logistics.java


public abstract class Logistics {
    // Factory Method
    public abstract Transport createTransport();

    // Common logic using product
    public void planDelivery() {
        Transport transport = createTransport();
        transport.deliver();
    }
}

Enter fullscreen mode Exit fullscreen mode

This is the factory class. It contains the planDelivery() method (business logic), but it defers the object creation to the createTransport() method β€” which is abstract and must be implemented by subclasses.

4. Concrete Factories β€” RoadLogistics.java and SeaLogistics.java


public class RoadLogistics extends Logistics {
    @Override
    public Transport createTransport() {
        return new Truck();
    }
}

Enter fullscreen mode Exit fullscreen mode

public class SeaLogistics extends Logistics {
    @Override
    public Transport createTransport() {
        return new Ship();
    }
}

Enter fullscreen mode Exit fullscreen mode

These are the specific factories. Each overrides the createTransport() method to return a specific transport type.

5. Client Code β€” Main.java


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

        // Land delivery
        logistics = new RoadLogistics();
        logistics.planDelivery();  // Output: Deliver by land in a box.

        // Sea delivery
        logistics = new SeaLogistics();
        logistics.planDelivery();  // Output: Deliver by sea in a container.
    }
}

Enter fullscreen mode Exit fullscreen mode

The client (main method) is not aware of which Transport is being used. It works with Logistics β€” which provides abstraction β€” and delegates creation to concrete classes.


Key Advantages

  • Encapsulation of object creation: The client never knows about Truck or Ship directly.
  • Extensible: Want to add AirLogistics? Just create another subclass β€” no need to change existing code.
  • Open/Closed Principle: Easy to add new types without modifying existing logic.

Consequences

  • More classes and complexity
  • Can be overkill for simple scenarios

When to Use

  • You want to delegate the instantiation process to child classes.
  • You need to localize the logic of object creation.
  • You want to avoid tight coupling between the client and concrete classes.

This is Part 2 of the Java Design Patterns Series.

If you find it insightful, please share your feedback. Also let me know if you have used factory pattern in your projects.

Next Up: Abstract Factory Method Pattern – Create objects without exposing the instantiation logic!

Top comments (0)