Factory Method Pattern in Java: Creating Objects Without Hardcoding new Everywhere

Learn the Factory Method Design Pattern in Java — what problem it solves, how it works, practical Java examples, benefits, drawbacks, and how modern frameworks like Spring internally use factory-based object creation.


In the previous article, we explored the Singleton Pattern — the most famous and often most misunderstood Creational Design Pattern.

Now let’s move to another extremely practical pattern that developers use almost every day, often without realizing it:

Factory Method Pattern

If Singleton answers:

“How do I ensure only one instance exists?”

Factory Method answers:

“How do I create objects without tightly coupling my code to concrete implementations?”

This pattern becomes incredibly useful as applications grow.


The Problem: Hardcoded Object Creation

Let’s begin with a real-world example.

Suppose you’re building a payment system.

Initial implementation:

public class PaymentService {

    public void process(String mode) {

        if(mode.equals("CARD")) {

            CardPayment payment =
                    new CardPayment();

            payment.pay();
        }

        else if(mode.equals("UPI")) {

            UpiPayment payment =
                    new UpiPayment();

            payment.pay();
        }
    }
}

Looks fine.

Until business requirements evolve.

Now product teams want:

  • Wallet Payments
  • PayPal
  • Stripe
  • Apple Pay
  • Google Pay

Your code starts growing.

if
else if
else if
else if
else if

Problems emerge.


Problems With Hardcoded new

1. Tight Coupling

Your service knows every implementation.

new CardPayment()
new UpiPayment()
new WalletPayment()

Service layer becomes coupled to concrete classes.


2. Difficult Extension

Adding a new payment method requires modifying existing logic.

Violates Open/Closed Principle.


3. Testing Becomes Harder

Mocking concrete dependencies becomes painful.


4. Scattered Creation Logic

Object creation spreads across the codebase.

Maintenance complexity increases.


This is exactly where Factory Method Pattern helps.


What is Factory Method Pattern?

Factory Method is a Creational Design Pattern that:

Delegates object creation to a dedicated method or factory component instead of directly using new.

Instead of writing:

new Object()

everywhere,

we centralize creation logic.


Basic Factory Method Implementation

Step 1 — Define Common Contract

public interface Payment {

    void pay();
}

Step 2 — Create Implementations

Card Payment

public class CardPayment
        implements Payment {

    public void pay() {

        System.out.println(
            "Card Payment Processed");
    }
}

UPI Payment

public class UpiPayment
        implements Payment {

    public void pay() {

        System.out.println(
            "UPI Payment Processed");
    }
}

Step 3 — Create Factory

public class PaymentFactory {

    public static Payment
        getPayment(String mode) {

        if(mode.equals("CARD"))
            return new CardPayment();

        if(mode.equals("UPI"))
            return new UpiPayment();

        throw new IllegalArgumentException(
                "Unsupported Payment");
    }
}

Step 4 — Use Factory

Service layer becomes cleaner.

public class PaymentService {

    public void process(String mode) {

        Payment payment =
            PaymentFactory
                .getPayment(mode);

        payment.pay();
    }
}

Notice what changed.

Service no longer knows:

CardPayment
UpiPayment
WalletPayment

It only understands:

Payment Interface

This reduces coupling significantly.


How Factory Method Works Internally

Think of Factory as a specialized object creation manager.

Instead of:

Client
   │
   ▼
new ConcreteClass()

we get:

Client
   │
   ▼
Factory
   │
   ▼
Concrete Object

Creation responsibility moves into one centralized place.


Real Engineering Example — Notification Service

Suppose your application sends notifications.

Without Factory:

public void notify(String type) {

    if(type.equals("EMAIL")) {

        EmailNotification email =
                new EmailNotification();

        email.send();
    }

    else if(type.equals("SMS")) {

        SmsNotification sms =
                new SmsNotification();

        sms.send();
    }
}

Again:

Growing conditionals.

Growing coupling.


Factory Version

Interface:

public interface Notification {

    void send();
}

Implementations:

public class EmailNotification
        implements Notification {

    public void send() {

        System.out.println(
            "Email Sent");
    }
}
public class SmsNotification
        implements Notification {

    public void send() {

        System.out.println(
            "SMS Sent");
    }
}

Factory:

public class NotificationFactory {

    public static Notification
        create(String type) {

        if(type.equals("EMAIL"))
            return new EmailNotification();

        if(type.equals("SMS"))
            return new SmsNotification();

        throw new IllegalArgumentException();
    }
}

Usage:

Notification notification =
        NotificationFactory
            .create("EMAIL");

notification.send();

Cleaner.

More maintainable.

More extensible.


Benefits of Factory Method Pattern

1. Reduced Coupling

Consumers depend on abstractions.

Not concrete implementations.


2. Centralized Creation Logic

All construction logic lives in one location.

Easier maintenance.


3. Improved Extensibility

Adding new implementations becomes easier.


4. Better Testability

Factories simplify dependency substitution.

Mocking becomes cleaner.


5. Supports Open/Closed Principle

You extend behavior.

You avoid modifying stable business logic.


Factory Method vs Direct Object Creation

Without Factory:

CardPayment payment =
        new CardPayment();

Problems:

✔ Hard dependency
✔ Concrete coupling
✔ Reduced flexibility


With Factory:

Payment payment =
    PaymentFactory
        .getPayment("CARD");

Benefits:

✔ Interface driven
✔ Cleaner abstraction
✔ Easier replacement


Where Factory Pattern Appears in Real Frameworks

You already use Factory concepts daily.


Java Calendar API

Example:

Calendar calendar =
        Calendar.getInstance();

You don’t create:

new GregorianCalendar()

directly.

Factory decides implementation.


Spring Framework

Spring container behaves heavily like a factory.

Example:

ApplicationContext

creates:

  • services
  • repositories
  • controllers
  • configuration beans

You usually do not write:

new UserService()

manually.

Spring manages creation.


JDBC DriverManager

Example:

Connection connection =
    DriverManager.getConnection();

Factory-based creation.


LoggerFactory

SLF4J example:

Logger log =
    LoggerFactory
        .getLogger(MyClass.class);

Another factory abstraction.


Factory Method vs Simple Factory

Many developers confuse these concepts.

Simple Factory

Single utility class.

PaymentFactory.getPayment()

Factory Method Pattern (GoF Version)

Uses inheritance.

Subclass controls creation.

Example structure:

Creator
   │
   ├── ConcreteCreatorA
   └── ConcreteCreatorB

This provides higher flexibility.

Most day-to-day Java applications often start with Simple Factory style.


Common Mistakes With Factory Pattern


Mistake 1 — Factory Explosion

Creating factories for trivial objects.

Overengineering risk.


Mistake 2 — Massive if-else Factories

Large factories become new bottlenecks.

Example:

1000 lines
50 conditions

Factory itself becomes messy.


Mistake 3 — Using Factory Without Need

Sometimes:

new User()

is perfectly acceptable.

Patterns should solve problems.

Not create complexity.


When Should You Use Factory Method?

Good candidates:

✔ Multiple implementations exist
✔ Object creation logic varies
✔ Runtime implementation selection needed
✔ Loose coupling required


Avoid when:

❌ Object creation is trivial
❌ No abstraction benefit exists
❌ Complexity outweighs value


Quick Comparison: Singleton vs Factory Method

PatternFocus
SingletonEnsure one instance
Factory MethodDelegate object creation

Singleton controls:

HOW MANY objects exist.

Factory controls:

HOW objects are created.

Final Thoughts

The Factory Method Pattern solves a very common engineering challenge:

How do we create objects cleanly without scattering new everywhere?

By centralizing creation logic, Factory patterns improve:

  • maintainability
  • flexibility
  • extensibility
  • testability

This is one reason factories appear heavily across:

  • Spring Framework
  • Java SDK
  • Logging libraries
  • JDBC
  • Enterprise applications

Once you begin recognizing factory-based design, you’ll notice it everywhere in Java ecosystems.

In the next article, we’ll continue our Creational Design Pattern deep dive with another highly practical pattern:

Builder Pattern — Constructing Complex Objects Without Constructor Chaos

Leave a Reply

Your email address will not be published. Required fields are marked *