Back to Creational: Singleton, Factory, Builder, Prototype
Q6Question 6 of 12

Explain the Factory design pattern with benefits and use cases

Key Concepts
  • Factory centralises object creation behind one place so callers ask by type, never writing new.
  • Three parts: product interface, concrete product classes, and a factory that decides which to instantiate.
  • Decouples client code from concrete classes: adding a product is adding a class, not editing callers.
  • Supports OCP: new products are new classes with one factory registration, leaving existing code untouched.
  • In modern Java, a Map of Supplier replaces the switch; in Spring, injecting a Map of bean name to interface is a factory for free.
  • Use cases: choosing implementation by config, abstracting creation in frameworks, hiding complex construction.

Definition

The Factory hides the new keyword behind one place, so callers ask for a product by type and get back an interface, and adding a new type is just adding a class.
  • Factory pattern – a creational pattern that centralises object creation behind a dedicated factory so callers request a product by key instead of using new.
  • Three parts – a product interface (common contract), concrete product classes (implementations), and a factory (decides which concrete product to create).
  • Decoupling – client code depends only on the interface and the factory, not on concrete classes.
  • OCP – adding a new product means adding a class and one factory entry; existing code is untouched.
  • Modern form – a Map> or Spring's Map bean injection.

At the National Bank of India there is one account-opening counter. Rajesh walks up and says "I want a savings account" or "I want a current account," and the clerk hands him the correct, fully prepared kit. Rajesh never goes into the back room to assemble the kit himself. The counter is the factory, the kit types are the concrete products, and the general idea of an account kit is the product interface.

Understanding the Concepts

What is the Factory pattern?

The Factory pattern has three parts: a product interface, concrete products, and a factory that maps an input to the right product.

JAVA
package com.bank.service;

// Product interface
public interface NotificationChannel {
    void send(String to, String message);
}

// Concrete products
public class SmsChannel implements NotificationChannel {
    public void send(String to, String message) {
        System.out.println("SMS to " + to + ": " + message);
    }
}

public class EmailChannel implements NotificationChannel {
    public void send(String to, String message) {
        System.out.println("Email to " + to + ": " + message);
    }
}

public class PushChannel implements NotificationChannel {
    public void send(String to, String message) {
        System.out.println("Push to " + to + ": " + message);
    }
}

// Factory
public class ChannelFactory {
    public static NotificationChannel create(String type) {
        return switch (type) {
            case "SMS" -> new SmsChannel();
            case "EMAIL" -> new EmailChannel();
            case "PUSH" -> new PushChannel();
            default -> throw new IllegalArgumentException("Unknown channel: " + type);
        };
    }
}

The caller writes ChannelFactory.create("SMS") and then channel.send(...), never knowing the concrete class.

What are the benefits of Factory?

  • Decoupling: client code depends only on the interface and the factory, not concrete classes.
  • Single point of change: creation logic lives in one method; adding a cache or parameter touches one place.
  • OCP: adding a channel means adding a class and one factory branch. Existing code is untouched.
  • Polymorphism: the factory returns the interface type, enabling clean polymorphic dispatch.
JAVA
package com.bank.service;

public class AlertService {
    // Depends only on NotificationChannel interface
    public void sendAlert(String channel, String to, String message) {
        NotificationChannel ch = ChannelFactory.create(channel);
        ch.send(to, message);
    }
}

What are common use cases?

  • Choosing an implementation by configuration: pick an SMS provider per region.
  • Abstracting creation in frameworks: Spring's bean container is a factory.
  • Hiding complex or conditional construction: building a parser based on file extension.
JAVA
package com.bank.demo;

public class FactoryUseCaseDemo {
    public static void main(String[] args) {
        // Customer preference determines the channel
        String preference = "SMS"; // from database
        NotificationChannel channel = ChannelFactory.create(preference);
        channel.send("+91-9876543210", "Your transfer of 50,000 INR is complete.");
    }
}
TEXT
SMS to +91-9876543210: Your transfer of 50,000 INR is complete.

How does Factory look in modern Java?

Replace the switch with a Map>:

JAVA
package com.bank.service;

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

public class ModernChannelFactory {
    private static final Map<String, Supplier<NotificationChannel>> REGISTRY = Map.of(
        "SMS", SmsChannel::new,
        "EMAIL", EmailChannel::new,
        "PUSH", PushChannel::new
    );

    public static NotificationChannel create(String type) {
        Supplier<NotificationChannel> supplier = REGISTRY.get(type);
        if (supplier == null) {
            throw new IllegalArgumentException("Unknown: " + type);
        }
        return supplier.get();
    }
}

The map is trivially extensible: adding a channel is adding one entry.

How does Factory work in Spring?

In Spring, injecting a Map gives a factory for free:

JAVA
package com.bank.service;

import org.springframework.stereotype.Service;
import java.util.Map;

@Service
public class SpringAlertService {
    private final Map<String, NotificationChannel> channels;

    public SpringAlertService(Map<String, NotificationChannel> channels) {
        this.channels = channels;
    }

    public void send(String channelName, String to, String message) {
        NotificationChannel ch = channels.get(channelName);
        if (ch == null) throw new IllegalArgumentException("Unknown: " + channelName);
        ch.send(to, message);
    }
}

Adding a new channel is adding a new @Component bean. No factory edit.

What are common mistakes with Factory?

  • Having the factory return concrete types instead of the interface, defeating the decoupling.
  • Over-using Factory for objects that have no variation: a plain new is simpler.
  • Putting business logic inside the factory instead of in the products.

How does Factory support testing?

Because the factory returns the interface, tests can create a mock or stub:

JAVA
// In tests
NotificationChannel mockChannel = (to, msg) -> System.out.println("MOCK: " + msg);
// inject mockChannel instead of calling the factory

What should a senior engineer know?

  • The switch-based factory is fine for a handful of types; the Map-based factory scales.
  • In Spring, the container itself is a factory. Understanding this makes the pattern feel natural.
  • Factory Method (GoF) specifically uses a method that subclasses override; the term "factory" in daily use is broader.
  • At National Bank of India, the alert factory was the fix for scattered new SmsChannel() calls that caused missed alerts when push notifications were added.

Visual Overview

DIAGRAM
  Factory Pattern Structure
  ─────────────────────────

  Client                         Factory
  ──────                         ───────
  AlertService ──▶ ChannelFactory.create("SMS")
       │                           │
       │                           ▼
       │                    ┌──────────────────┐
       │                    │ NotificationChannel│ ◄── interface
       │                    └────────┬─────────┘
       │                             │
       │                  ┌──────────┼──────────┐
       │                  ▼          ▼          ▼
       │             SmsChannel EmailChannel PushChannel
       │
       ▼
  channel.send(to, msg)   ◄── works with any channel

Key Takeaway

The Factory pattern centralises object creation behind one place, so calling code asks for a product by type instead of using new directly. It has three parts: a product interface that defines the common contract, concrete product classes that implement it, and a factory that decides which one to create.

The benefits are decoupling, a single point of change, OCP compliance, and clean polymorphism. At National Bank of India, Rajesh had alert-sending code scattered with new SmsChannel() in many places. When push notifications were added, some code paths were missed and customers never got alerts. He fixed it with a ChannelFactory, so every alert goes through one factory. Adding WhatsApp was a new class plus one registry entry, with every existing alert untouched.

In modern Java, the factory switch is replaced by a Map>, and in Spring, injecting a Map gives a factory for free. Adding a new channel is literally adding a new @Component bean.

The senior judgment is to use Factory when there is real variation in which concrete type to create, and to keep a plain new when there is no variation. Over-applying Factory adds indirection for no benefit.

Remember one sentence: Factory hides the new keyword behind one place, so callers depend only on the interface and adding a product is adding a class, not editing callers.

---

Share
Use ← → arrow keys to navigate