← Back to principles

Design Principle

Factory Pattern: Principles, Trade-offs & Examples

Learn the Factory pattern: create objects without specifying exact classes. Master Factory Method and Abstract Factory patterns with practical examples.

Factory Pattern

Why This Matters

Think of the Factory pattern like a restaurant kitchen. You don't tell the kitchen "make me a pizza with these exact ingredients and cooking method." You just say "I want a pizza," and the kitchen (factory) decides how to make it. The Factory pattern does the same for code—you don't specify the exact class to create, you just ask for an object, and the factory creates it.

This matters because object creation can be complex. You might need to choose between different implementations based on configuration, environment, or runtime conditions. The Factory pattern encapsulates this complexity, making your code simpler and more flexible. When you need to add a new type, you just add it to the factory, not everywhere you create objects.

In interviews, when someone asks "How would you refactor this code?", they're testing whether you understand the Factory pattern. Can you identify when object creation is complex? Can you encapsulate it in a factory? Most engineers can't. They create objects directly and wonder why the code is hard to change.

What Engineers Usually Get Wrong

Engineers often think "Factory pattern means always use factories." But factories add indirection. If object creation is simple and unlikely to change, direct instantiation is fine. Use factories when creation is complex, when you need to choose between implementations, or when creation logic might change.

Engineers also confuse Factory Method with Abstract Factory. Factory Method creates one type of object (e.g., create a payment processor). Abstract Factory creates families of related objects (e.g., create a payment processor AND a payment validator). Understanding the difference helps you choose the right pattern.

How This Breaks Systems in the Real World

A service was creating payment processors directly: new CreditCardProcessor(), new PayPalProcessor(), etc. The creation logic was scattered across the codebase. When the team needed to add logging or metrics to all processors, they had to modify code in 20 places. The fix? Use a Factory pattern. Centralize creation logic in one place. Now adding logging or metrics requires changes in only one place.

Another story: A service was using if/else statements to choose which payment processor to create. As more payment methods were added, the if/else chain grew to 50 lines. It became hard to understand and maintain. The fix? Use a Factory pattern with a registry. Register payment processors in a map, and the factory looks them up. Adding a new payment method is now just registering it, not modifying a long if/else chain.


What is the Factory Pattern?

Factory Pattern provides:

  • Encapsulation: Encapsulates object creation logic
  • Decoupling: Decouples object creation from usage
  • Flexibility: Easy to add new types
  • Centralization: Centralizes object creation logic

Types:

  • Factory Method: Subclasses decide which class to instantiate
  • Abstract Factory: Provides interface for creating families of related objects

Factory Method Pattern

Factory Method lets subclasses decide which class to instantiate.

Structure

Creator (abstract)
  ├─ factoryMethod() (abstract)
  └─ createProduct() (uses factoryMethod)

ConcreteCreator
  └─ factoryMethod() (returns ConcreteProduct)

Product (interface)
ConcreteProduct (implements Product)

Examples

Factory Method Example

TypeScript
Python
Java
1

Simple Factory Example

TypeScript
Python
Java
1

Abstract Factory Pattern

TypeScript
Python
Java
1

Common Pitfalls

  • Over-engineering: Using factory for simple cases. Fix: Use factory only when needed
  • Tight coupling: Factory still coupled to concrete classes. Fix: Use interfaces, dependency injection
  • Complexity: Abstract Factory can be complex. Fix: Use only when creating families of objects
  • Not extensible: Hard to add new types. Fix: Use open-closed principle, registry pattern

Interview Questions

Beginner

Q: What is the Factory pattern and why is it useful?

A:

Factory Pattern provides an interface for creating objects without specifying their exact classes.

Benefits:

  • Encapsulation: Encapsulates object creation logic
  • Decoupling: Decouples object creation from usage
  • Flexibility: Easy to add new types
  • Centralization: Centralizes creation logic

Example:

TypeScript
Python
Java
1

Use cases:

  • Object creation complexity: Complex object creation
  • Multiple types: Creating different types of objects
  • Decoupling: Decouple creation from usage
  • Configuration: Creation based on configuration

Intermediate

Q: Explain the difference between Factory Method and Abstract Factory patterns. When would you use each?

A:

Factory Method Pattern:

Lets subclasses decide which class to instantiate:

TypeScript
Python
Java
1

Use when:

  • Single product family: Creating one type of product
  • Subclass responsibility: Subclasses decide what to create
  • Flexibility: Need flexibility in product creation

Abstract Factory Pattern:

Provides interface for creating families of related objects:

TypeScript
Python
Java
1

Use when:

  • Multiple product families: Creating families of related objects
  • Consistency: Need consistent products from same family
  • Platform-specific: Different implementations for different platforms

Key Differences:

FeatureFactory MethodAbstract Factory
ProductsSingle productFamily of products
ComplexitySimplerMore complex
Use caseOne product typeMultiple related products

Senior

Q: Design a factory system for a plugin architecture where plugins can be loaded dynamically. How do you handle plugin registration, creation, and ensure type safety?

A:

TypeScript
Python
Java
1

Features:

  1. Plugin registry: Register and store plugins
  2. Dynamic loading: Load plugins at runtime
  3. Type safety: Validate plugin structure
  4. Factory: Create plugins by name

Failure Stories You'll Recognize

The Scattered Creation Logic: A service was creating payment processors directly: new CreditCardProcessor(), new PayPalProcessor(), etc. The creation logic was scattered across the codebase. When the team needed to add logging or metrics to all processors, they had to modify code in 20 places. The fix? Use a Factory pattern. Centralize creation logic in one place. Now adding logging or metrics requires changes in only one place.

The If/Else Chain: A service was using if/else statements to choose which payment processor to create. As more payment methods were added, the if/else chain grew to 50 lines. It became hard to understand and maintain. The fix? Use a Factory pattern with a registry. Register payment processors in a map, and the factory looks them up. Adding a new payment method is now just registering it, not modifying a long if/else chain.

The Over-Engineered Factory: A team created a complex factory system for simple object creation. The factory had 10 layers of abstraction, making it hard to understand and debug. Simple object creation required understanding the entire factory hierarchy. The fix? Simplify. Use factories only when creation is complex or likely to change. For simple creation, direct instantiation is fine.

What Interviewers Are Really Testing

They want to hear you talk about factories as a tool for managing complexity, not a rule to always follow. Junior engineers say "use factories for object creation." Senior engineers say "factories encapsulate creation logic and make code more flexible. Use them when creation is complex or likely to change. Don't over-engineer—simple creation doesn't need factories."

When they ask "How would you refactor this code?", they're testing:

  • Can you identify when object creation is complex?
  • Do you know when to use factories vs direct instantiation?
  • Can you design factories that are simple and maintainable?

Keep exploring

Principles work best in chorus. Pair this lesson with another concept and observe how your architecture conversations change.