Back to Design Patterns
Creational Pattern

Factory Method Pattern

Define an interface for creating objects, but let subclasses decide which class to instantiate.

Beginner Friendly10 min read

What is the Factory Method Pattern?

The Factory Method pattern is a creational design pattern that provides an interface for creating objects in a superclass, but allows subclasses to alter the type of objects that will be created.

Instead of calling a constructor directly, you call a factory method which returns the object. This gives subclasses the power to decide which concrete class to instantiate.

Key Idea: Define a method for creating objects, but let subclasses choose the actual type. The parent class doesn't know the exact class of the object it creates.

!Problem It Solves

Tight Coupling Problem

Without Factory Method, your code is tightly coupled to specific classes. Adding new types requires modifying existing code:

// Problem: Hard-coded object creation
public class PaymentService {
    public void processPayment(String type, double amount) {
        if (type.equals("stripe")) {
            StripeGateway gateway = new StripeGateway();
            gateway.process(amount);
        } else if (type.equals("paypal")) {
            PayPalGateway gateway = new PayPalGateway();
            gateway.process(amount);
        }
        // Adding new gateway? Must modify this method!
    }
}

Issues with This Approach

  • → Violates Open/Closed Principle (must modify existing code)
  • → Hard to test (can't mock specific gateway types)
  • → Code duplication across different modules
  • → Difficult to maintain as system grows

How It Works

Structure

1

Product Interface

Declares the interface for objects the factory method creates

2

Concrete Products

Implement the Product interface (StripeGateway, PayPalGateway)

3

Creator

Declares the factory method that returns Product objects

4

Concrete Creators

Override factory method to return specific products

Implementation

// Product Interface
interface PaymentGateway {
    void processPayment(double amount);
    boolean validateCredentials();
}

// Concrete Products
class StripePaymentGateway implements PaymentGateway {
    @Override
    public void processPayment(double amount) {
        System.out.println("Processing $" + amount + " through Stripe");
    }
    
    @Override
    public boolean validateCredentials() {
        System.out.println("Validating Stripe API keys");
        return true;
    }
}

class PayPalPaymentGateway implements PaymentGateway {
    @Override
    public void processPayment(double amount) {
        System.out.println("Processing $" + amount + " through PayPal");
    }
    
    @Override
    public boolean validateCredentials() {
        System.out.println("Validating PayPal credentials");
        return true;
    }
}

class RazorpayPaymentGateway implements PaymentGateway {
    @Override
    public void processPayment(double amount) {
        System.out.println("Processing ₹" + amount + " through Razorpay");
    }
    
    @Override
    public boolean validateCredentials() {
        System.out.println("Validating Razorpay keys");
        return true;
    }
}

// Creator Abstract Class
abstract class PaymentProcessor {
    // Factory Method (to be implemented by subclasses)
    protected abstract PaymentGateway createPaymentGateway();
    
    // Template method using factory method
    public void executePayment(double amount) {
        PaymentGateway gateway = createPaymentGateway();
        
        if (gateway.validateCredentials()) {
            gateway.processPayment(amount);
            System.out.println("Payment successful!");
        } else {
            System.out.println("Payment failed: Invalid credentials");
        }
    }
}

// Concrete Creators
class StripePaymentProcessor extends PaymentProcessor {
    @Override
    protected PaymentGateway createPaymentGateway() {
        return new StripePaymentGateway();
    }
}

class PayPalPaymentProcessor extends PaymentProcessor {
    @Override
    protected PaymentGateway createPaymentGateway() {
        return new PayPalPaymentGateway();
    }
}

class RazorpayPaymentProcessor extends PaymentProcessor {
    @Override
    protected PaymentGateway createPaymentGateway() {
        return new RazorpayPaymentGateway();
    }
}

// Usage Example
public class ECommerceApp {
    public static void main(String[] args) {
        // Client code works with processors through abstract interface
        PaymentProcessor processor;
        
        String paymentMethod = "stripe"; // Could come from user selection
        
        // Choose processor based on configuration
        if (paymentMethod.equals("stripe")) {
            processor = new StripePaymentProcessor();
        } else if (paymentMethod.equals("paypal")) {
            processor = new PayPalPaymentProcessor();
        } else {
            processor = new RazorpayPaymentProcessor();
        }
        
        // Process payment (subclass handles gateway creation)
        processor.executePayment(100.00);
    }
}

When to Use Factory Method

Multiple Payment Gateways

Switch between Stripe, PayPal, Razorpay without changing business logic

E-commerce checkout systems

Notification Systems

Send notifications via Email, SMS, Push, or Slack

Alert and messaging platforms

Database Connectors

Connect to MySQL, PostgreSQL, MongoDB based on configuration

ORM libraries, data access layers

Document Generators

Generate PDF, Excel, CSV reports with same interface

Reporting and export systems

UI Frameworks

Create platform-specific UI components (Web, iOS, Android)

Cross-platform application development

Pros & Cons

Advantages

  • Loose coupling between creator and products
  • Open/Closed Principle - easy to add new products
  • Single Responsibility - creation logic separated
  • Easier to test and maintain

Disadvantages

  • Can make code more complex with many classes
  • Requires creating subclasses for each product type
  • May be overkill for simple scenarios

Real-World Examples

Java Collections Framework

Iterator interface with iterator() factory method lets each collection return its specific iterator implementation

React.createElement()

Factory method that creates React elements based on type - can be DOM elements, components, or fragments

Django ORM

Database backends use factory methods to create database-specific connections and query builders

What's Next?

You've mastered Creational patterns! Continue exploring: