Skip to content
intermediatePhase 49 · Low-Level Design

Factory Pattern

Create objects without specifying exact classes in the creation logic.

30m
0 problems
Topic Progress0%

Simple Factory

A Simple Factory encapsulates object creation logic in a single method. It's not a GoF pattern but widely used.

Basic Implementation

// Simple Factory
public class NotificationFactory {
    public static Notification create(NotificationType type) {
        return switch (type) {
            case EMAIL -> new EmailNotification();
            case SMS -> new SMSNotification();
            case PUSH -> new PushNotification();
        };
    }
}

// Usage
Notification notification = NotificationFactory.create(NotificationType.EMAIL);
notification.send("Hello!");

When to Use

  • You need a single method to create different types
  • Object creation logic is complex
  • You want to centralize creation decisions
  • Different conditions determine which object to create

Advantages

  1. Encapsulation: Client doesn't need to know concrete classes
  2. Centralization: Creation logic in one place
  3. Flexibility: Easy to add new types
  4. Readability: Clear intent

Limitations

  1. Violation of Open-Closed: Adding new types requires modifying factory
  2. Single responsibility: Factory has too many creation methods

Example: Payment Processing

public class PaymentProcessorFactory {
    public static PaymentProcessor create(PaymentType type) {
        return switch (type) {
            case CREDIT_CARD -> new CreditCardProcessor();
            case PAYPAL -> new PayPalProcessor();
            case BITCOIN -> new BitcoinProcessor();
        };
    }
}

// Client code
PaymentProcessor processor = PaymentProcessorFactory.create(user.getPaymentType());
processor.processPayment(order.getTotal());

Factory Method

Factory Method defines an interface for creating objects but lets subclasses decide which class to instantiate.

Implementation

// Creator abstract class
public abstract class NotificationSender {
    // Factory Method
    protected abstract Notification createNotification();
    
    public void sendNotification(String message) {
        Notification notification = createNotification();
        notification.send(message);
    }
}

// Concrete creators
class EmailSender extends NotificationSender {
    @Override
    protected Notification createNotification() {
        return new EmailNotification();
    }
}

class SMSSender extends NotificationSender {
    @Override
    protected Notification createNotification() {
        return new SMSNotification();
    }
}

// Usage
NotificationSender sender = new EmailSender();
sender.sendNotification("Hello!");

How It Works

NotificationSender (abstract)
│
│ + sendNotification(message)
│   │
│   └── createNotification()  ← Factory Method
│         ▲                    (abstract)
│         │
├─────────┴──────────┐
│                    │
EmailSender       SMSSender
│                    │
└── createNotification()  └── createNotification()
    returns EmailNotification  returns SMSNotification

When to Use

  • A class can't anticipate the type of objects it needs to create
  • You want subclasses to specify the objects to create
  • You need to delegate creation responsibility to subclasses

Real-World Example

// Document types
abstract class Document {
    abstract Page createPage();
}

class Resume extends Document {
    Page createPage() { return new ResumePage(); }
}

class Report extends Document {
    Page createPage() { return new ReportPage(); }
}

// Creator
abstract class DocumentFactory {
    abstract Document createDocument();
    
    void printDocument() {
        Document doc = createDocument();
        // Process document...
    }
}

Abstract Factory

Abstract Factory provides an interface for creating families of related objects without specifying their concrete classes.

Implementation

// Abstract Factory
public interface GUIFactory {
    Button createButton();
    TextBox createTextBox();
    CheckBox createCheckBox();
}

// Concrete Factories
public class WindowsFactory implements GUIFactory {
    public Button createButton() { return new WindowsButton(); }
    public TextBox createTextBox() { return new WindowsTextBox(); }
    public CheckBox createCheckBox() { return new WindowsCheckBox(); }
}

public class MacFactory implements GUIFactory {
    public Button createButton() { return new MacButton(); }
    public TextBox createTextBox() { return new MacTextBox(); }
    public CheckBox createCheckBox() { return new MacCheckBox(); }
}

// Usage
GUIFactory factory = isWindows() ? new WindowsFactory() : new MacFactory();
Button button = factory.createButton();
button.render();

Family of Objects

GUIFactory
├── WindowsFactory
│   ├── WindowsButton
│   ├── WindowsTextBox
│   └── WindowsCheckBox
│
└── MacFactory
    ├── MacButton
    ├── MacTextBox
    └── MacCheckBox

All objects from the same factory are compatible

When to Use

  • System must be independent of how objects are created
  • System must work with multiple families of objects
  • You need to enforce constraints about which objects are used together

Example: Database Abstraction

public interface DatabaseFactory {
    Connection createConnection();
    QueryBuilder createQueryBuilder();
    MigrationRunner createMigrationRunner();
}

public class PostgresFactory implements DatabaseFactory {
    public Connection createConnection() { return new PostgresConnection(); }
    public QueryBuilder createQueryBuilder() { return new PostgresQueryBuilder(); }
    public MigrationRunner createMigrationRunner() { return new PostgresMigration(); }
}

public class MySQLFactory implements DatabaseFactory {
    public Connection createConnection() { return new MySQLConnection(); }
    public QueryBuilder createQueryBuilder() { return new MySQLQueryBuilder(); }
    public MigrationRunner createMigrationRunner() { return new MySQLMigration(); }
}

When to Use

Choosing the right factory pattern depends on the specific problem you're solving.

Decision Matrix

┌─────────────────────────────────────────────────────────────┐
│                Factory Pattern Selection                     │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Simple Factory:                                            │
│  - Single creation method                                   │
│  - Don't need subclass flexibility                          │
│  - Simple switch/if-else creation                           │
│                                                             │
│  Factory Method:                                            │
│  - Subclass decides which class to instantiate              │
│  - You don't know exact types beforehand                    │
│  - Want to delegate creation to subclasses                  │
│                                                             │
│  Abstract Factory:                                          │
│  - Need families of related objects                         │
│  - Objects must be used together                            │
│  - Multiple product variants                                │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Comparison Table

Aspect Simple Factory Factory Method Abstract Factory
GoF Pattern No Yes Yes
Creation Single method Subclass method Interface
Flexibility Moderate High Very High
Complexity Low Medium High
Adding types Modify factory Add subclass Add factory

Common Use Cases

Use Case Pattern
Different notification types Simple Factory
Document format creation Factory Method
Cross-platform UI components Abstract Factory
Payment processor selection Simple Factory
Plugin loading Factory Method
Database driver creation Abstract Factory

Anti-Patterns

  1. Overuse: Don't use factory when new is sufficient
  2. God Factory: One factory creating everything
  3. Leaking types: Factory returns concrete type instead of interface
  4. Complex conditions: Too many if/else in factory method

Refactoring to Factory

// Before: scattered creation
public class OrderService {
    public void processPayment(Order order) {
        if (order.getPaymentType() == CREDIT_CARD) {
            new CreditCardProcessor().process(order);
        } else if (order.getPaymentType() == PAYPAL) {
            new PayPalProcessor().process(order);
        }
    }
}

// After: centralized in factory
public class OrderService {
    private final PaymentProcessorFactory factory;
    
    public void processPayment(Order order) {
        factory.create(order.getPaymentType()).process(order);
    }
}

Practice Problems

0/3solved
Design Factory Pattern System

Design a scalable Factory Pattern system. Cover high-level architecture, data model, and API design.

Solution
// Complete system design:
// - Functional + Non-functional requirements
// - Capacity estimation
// - Data model (SQL/NoSQL choice)
// - API endpoints
// - Component architecture
// - Scaling strategy
// - Monitoring & reliability
Factory Pattern Scaling

How would you scale Factory Pattern to handle 10x the current load? Identify bottlenecks and solutions.

Solution
// Scaling approach:
// 1. Load balancing
// 2. Database sharding/replication
// 3. Cache layer (Redis)
// 4. CDN for static assets
// 5. Async processing (queues)
// 6. Microservices decomposition
Factory Pattern Failure Modes

Analyze potential failure modes for Factory Pattern and design mitigation strategies.

Solution
// Failure mitigation:
// 1. Redundancy (multi-AZ)
// 2. Circuit breakers
// 3. Retry with backoff
// 4. Dead letter queues
// 5. Health checks
// 6. Graceful degradation

Quiz

1. What is the difference between Simple Factory and Factory Method?

Question 1 options

2. When should you use Abstract Factory?

Question 2 options

3. What problem does Factory Method solve?

Question 3 options

4. What is an anti-pattern for factory usage?

Question 4 options

5. What is a Simple Factory limitation?

Question 5 options

Flashcards

Question

What is a Simple Factory?

Answer

A single method that encapsulates object creation logic. Not a GoF pattern but widely used. Centralizes creation decisions.

Question

What is Factory Method?

Answer

Defines an interface for creating objects but lets subclasses decide which class to instantiate. Uses abstract creation method.

Question

What is Abstract Factory?

Answer

Provides an interface for creating families of related objects without specifying concrete classes. Ensures compatibility between created objects.

Question

When to use Factory Method vs Abstract Factory?

Answer

Factory Method: subclass decides single object. Abstract Factory: create families of related objects that must be compatible.

Question

What is a factory anti-pattern?

Answer

Revision Notes

Key Takeaways

  • 1.Simple Factory centralizes creation in a single method
  • 2.Factory Method lets subclasses decide which class to instantiate
  • 3.Abstract Factory creates families of related compatible objects
  • 4.Choose based on flexibility needs and object relationships
  • 5.Don't overuse factories — use `new` when sufficient

Interview Tips

  • Explain which factory pattern fits the problem and why
  • Show how factories enable adding new types without modifying client code
  • Discuss how factories support testing through dependency injection
  • Mention when NOT to use factories (simple creation scenarios)

Cheat Sheet

Factory Pattern - Cheat Sheet

Simple Factory:

  • Single creation method
  • switch/if-else for types
  • Not GoF pattern
  • Violates OCP when adding types

Factory Method:

  • Abstract creation method
  • Subclasses decide class
  • GoF pattern
  • Flexible, extensible

Abstract Factory:

  • Interface for object families
  • Related objects must be compatible
  • GoF pattern
  • Multiple product variants

Selection:

Need Pattern
Simple creation Simple Factory
Subclass decides Factory Method
Object families Abstract Factory

Use When:

  • Don't know exact types
  • Complex creation logic
  • Need flexibility
  • Objects must be compatible