Skip to main content

Command Palette

Search for a command to run...

The Factory Pattern .

Creating objects without exposing the creation logic.

Updated
4 min read
The Factory Pattern .

Have you ever found yourself writing too many new statements all over your code — creating objects manually every time you need them?

If yes, then you’ve probably faced this problem:

“Every time I add a new type of object, I need to change multiple places in the code. It becomes messy and tightly coupled.”

This is a common pain point in software design. The Factory Design Pattern is here to fix that.

// Step 1: Common Interface
public interface Notification {
    void send(String message);
}

// Step 2: Concrete Classes
public class EmailNotification implements Notification {
    public void send(String message) {
        System.out.println("Sending EMAIL: " + message);
    }
}

public class SMSNotification implements Notification {
    public void send(String message) {
        System.out.println("Sending SMS: " + message);
    }
}

public class PushNotification implements Notification {
    public void send(String message) {
        System.out.println("Sending PUSH: " + message);
    }
}

// Step 3: Factory Class
public class NotificationFactory {
    public static Notification createNotification(String type) {
        if (type == null || type.isEmpty()) return null;
        switch (type.toUpperCase()) {
            case "EMAIL": return new EmailNotification();
            case "SMS": return new SMSNotification();
            case "PUSH": return new PushNotification();
            default: throw new IllegalArgumentException("Unknown notification type " + type);
        }
    }
}

// Step 4: Client Code
public class Main {
    public static void main(String[] args) {
        Notification notification = NotificationFactory.createNotification("EMAIL");
        notification.send("Factory Pattern in Action!");
    }
}

🧠 What Just Happened?

Now, your Main or NotificationService doesn’t need to know how notifications are created — it just asks the factory for one.

If tomorrow you add WhatsAppNotification, you just update the factory, not every place in your app.

Important for the Spring Boot developer

💬 Your Question:

“If we’re using frameworks like Spring, then we don’t face the problem of using new everywhere. So, do we still need the Factory Pattern?”

Let’s unpack this clearly — because this is exactly where most developers get confused when learning design patterns in the age of frameworks like Spring Boot.

Spring itself already uses the Factory Pattern internally — that’s why you don’t have to use new.
But understanding the Factory Pattern is still essential — because Spring’s entire dependency injection system is built on top of it.

🧩 Without Spring — Manual Object Creation

When you don’t use Spring, you do something like this:

Notification notification = new EmailNotification();
notification.send("Hello!");

or

if (type.equals("SMS")) {
    notification = new SMSNotification();
}

👉 You’re manually creating objects with new.
If you add a new type tomorrow, you have to modify your code — it’s tightly coupled.


🏭 With Spring — Factory in Action (But Hidden)

When you use Spring:

@Service
public class NotificationService {
    @Autowired
    private Notification notification;
}

You never write new EmailNotification() — right?

That’s because the Spring Container (ApplicationContext) acts like a Super Factory:

  • It creates objects for you (beans).

  • It decides which implementation to inject.

  • It manages their lifecycle (singleton, prototype, etc.).

Under the Hood

Spring uses:

  • BeanFactory → The root factory that creates and manages beans.

  • ApplicationContext → A more advanced factory that supports AOP, events, and message sources.

So yes — the Factory Pattern is at the core of Spring’s architecture.
You don’t see it, but it’s running behind every @Autowired.


🧠 Why You Should Still Learn the Factory Pattern

Even though Spring handles object creation for you, understanding the Factory Pattern helps you:

  1. Understand Spring’s internals
    → You’ll know how BeanFactory, ApplicationContext, and dependency injection work.

  2. Write cleaner custom factories
    → Sometimes, you still need to decide at runtime which object to create based on user input or configuration.
    Example: Payment gateway selector — Stripe, Razorpay, or PayPal.

     public interface PaymentGateway { void pay(); }
    
     public class StripeGateway implements PaymentGateway { public void pay() { ... } }
     public class RazorpayGateway implements PaymentGateway { public void pay() { ... } }
    
     @Component
     public class PaymentFactory {
         public PaymentGateway getGateway(String type) {
             return switch (type) {
                 case "STRIPE" -> new StripeGateway();
                 case "RAZORPAY" -> new RazorpayGateway();
                 default -> throw new IllegalArgumentException("Unknown gateway: " + type);
             };
         }
     }
    

    You can still inject this factory into services, but the decision logic is yours.

  3. Design framework-agnostic systems
    → In interviews or low-level architecture design, you may be asked to design without frameworks.
    Understanding the pattern helps you explain and design the logic yourself.

🏁 Final Thought

“If you find yourself changing the same class every time you add a new type of object — it’s time to use the Factory Pattern.”

The Factory Design Pattern helps you build clean, maintainable, and scalable systems by letting your code focus on behavior, not object creation.