Factory Pattern
Factory Pattern: Creating Objects the Smart Way
Section titled “Factory Pattern: Creating Objects the Smart Way”Now let’s dive into the Factory Pattern - one of the most commonly used creational design patterns.
Why Factory Pattern?
Section titled “Why Factory Pattern?”Imagine you’re ordering a pizza. You don’t need to know how the kitchen makes it - you just tell them “I want a pizza” and they handle the rest. The Factory Pattern works the same way!
The Factory Pattern lets you create objects without specifying their exact class. Instead of directly creating objects with new ClassName(), you ask a factory to create them for you.
What’s the Use of Factory Pattern?
Section titled “What’s the Use of Factory Pattern?”The Factory Pattern is useful when:
- You don’t know the exact type of object you need until runtime
- Object creation is complex - Lots of setup or configuration needed
- You want to decouple object creation from object usage
- You need flexibility - Easy to add new types without changing existing code
- You want centralized control - All object creation happens in one place
What Happens If We Don’t Use Factory Pattern?
Section titled “What Happens If We Don’t Use Factory Pattern?”Without the Factory Pattern, you might:
- Scatter object creation throughout your code
- Tightly couple your code to specific classes
- Make it hard to add new types - Need to modify code everywhere
- Duplicate creation logic - Same setup code in multiple places
- Violate Open/Closed Principle - Need to modify code to extend functionality
Simple Example: The Pizza Shop
Section titled “Simple Example: The Pizza Shop”Let’s start with a super simple example that anyone can understand!
Visual Representation
Section titled “Visual Representation”Interaction Flow
Section titled “Interaction Flow”Here’s how the Factory Pattern works in practice - showing the sequence of interactions:
sequenceDiagram
participant Client
participant Factory as PizzaFactory
participant Interface as Pizza Interface
participant Concrete as ConcretePizza
Client->>Factory: create_pizza("margherita")
activate Factory
Factory->>Concrete: new MargheritaPizza()
activate Concrete
Concrete-->>Factory: Pizza instance
deactivate Concrete
Factory-->>Client: Returns Pizza instance
deactivate Factory
Client->>Interface: pizza.prepare()
activate Interface
Interface-->>Client: "Preparing Margherita pizza..."
deactivate Interface
Note over Client,Concrete: Client doesn't know<br/>about concrete classes!
The Problem
Section titled “The Problem”You’re building a pizza ordering system. Customers can order different types of pizzas (Margherita, Pepperoni, Veggie). Without a factory, you’d do this:
Problems:
- Need to modify
order_pizza()every time you add a new pizza type - Creation logic is scattered
- Hard to test - can’t easily swap implementations
- Violates Open/Closed Principle
The Solution: Factory Pattern
Section titled “The Solution: Factory Pattern”Class Structure
Section titled “Class Structure”classDiagram
class Pizza {
<<abstract>>
+prepare() str
}
class MargheritaPizza {
+prepare() str
}
class PepperoniPizza {
+prepare() str
}
class VeggiePizza {
+prepare() str
}
class PizzaFactory {
+create_pizza(type) Pizza
}
class Client {
+order_pizza(type) str
}
Pizza <|-- MargheritaPizza : implements
Pizza <|-- PepperoniPizza : implements
Pizza <|-- VeggiePizza : implements
PizzaFactory ..> Pizza : creates
Client --> PizzaFactory : uses
Client ..> Pizza : uses
Real-World Software Example: Payment Processing System
Section titled “Real-World Software Example: Payment Processing System”Now let’s see a realistic software example - a payment processing system that needs to handle different payment methods.
The Problem
Section titled “The Problem”You’re building an e-commerce system that needs to process payments through different gateways (Stripe, PayPal, Square). Without Factory Pattern:
Problems:
- Complex creation logic scattered throughout code
- Need to know different initialization requirements for each gateway
- Hard to add new payment gateways
- Configuration management is messy
- Tight coupling to specific payment classes
The Solution: Factory Pattern
Section titled “The Solution: Factory Pattern”Adding a New Payment Gateway
Section titled “Adding a New Payment Gateway”With Factory Pattern, adding a new gateway is super easy:
Factory Pattern Variants
Section titled “Factory Pattern Variants”There are several variations of the Factory Pattern:
1. Simple Factory (Static Factory Method)
Section titled “1. Simple Factory (Static Factory Method)”The simplest form - a single method that creates objects:
2. Factory Method Pattern
Section titled “2. Factory Method Pattern”Each product has its own factory:
Creates families of related objects:
When to Use Factory Pattern?
Section titled “When to Use Factory Pattern?”Use Factory Pattern when:
✅ Object creation is complex - Lots of setup, configuration, or validation
✅ You don’t know the exact type until runtime
✅ You want to decouple creation from usage
✅ You need flexibility - Easy to add new types
✅ You want centralized control - All creation in one place
✅ You’re following Open/Closed Principle - Open for extension, closed for modification
When NOT to Use Factory Pattern?
Section titled “When NOT to Use Factory Pattern?”Don’t use Factory Pattern when:
❌ Simple object creation - If new Class() is enough, don’t overcomplicate
❌ Only one type - If you only ever create one type, factory is unnecessary
❌ Creation logic is trivial - Don’t add abstraction for simple cases
❌ Performance is critical - Factory adds a small overhead (usually negligible)
Common Mistakes to Avoid
Section titled “Common Mistakes to Avoid”Mistake 1: Over-Complicating Simple Cases
Section titled “Mistake 1: Over-Complicating Simple Cases”Mistake 2: Factory Creating Wrong Types
Section titled “Mistake 2: Factory Creating Wrong Types”Mistake 3: Factory with Too Many Responsibilities
Section titled “Mistake 3: Factory with Too Many Responsibilities”Benefits of Factory Pattern
Section titled “Benefits of Factory Pattern”- Decoupling - Client code doesn’t depend on concrete classes
- Flexibility - Easy to add new types without changing existing code
- Centralized Control - All creation logic in one place
- Hides Complexity - Client doesn’t need to know creation details
- Testability - Easy to mock factories for testing
- Follows SOLID Principles - Especially Open/Closed and Dependency Inversion
Revision: Quick Catch-Up
Section titled “Revision: Quick Catch-Up”What is Factory Pattern?
Section titled “What is Factory Pattern?”Factory Pattern is a creational design pattern that provides an interface for creating objects without specifying their exact classes. The factory decides which class to instantiate based on the input.
Why Use It?
Section titled “Why Use It?”- ✅ Decouple object creation from usage
- ✅ Centralize creation logic
- ✅ Simplify adding new types
- ✅ Hide complex initialization
- ✅ Follow Open/Closed Principle
How It Works?
Section titled “How It Works?”- Define an interface - What all products can do
- Create concrete classes - Specific implementations
- Create a factory - Handles object creation
- Use the factory - Client asks factory to create objects
Key Components
Section titled “Key Components”Client → Factory → Interface → Concrete Classes- Client - Uses the factory to get objects
- Factory - Creates objects based on input
- Interface - Defines what products can do
- Concrete Classes - Specific implementations
Simple Example
Section titled “Simple Example”# Interfaceclass Pizza(ABC): @abstractmethod def prepare(self): pass
# Concrete classesclass MargheritaPizza(Pizza): ...class PepperoniPizza(Pizza): ...
# Factoryclass PizzaFactory: @staticmethod def create(type: str) -> Pizza: if type == "margherita": return MargheritaPizza() # ...
# Usagepizza = PizzaFactory.create("margherita")When to Use?
Section titled “When to Use?”✅ Complex object creation
✅ Runtime type determination
✅ Need flexibility to add new types
✅ Want to decouple creation from usage
✅ Following Open/Closed Principle
When NOT to Use?
Section titled “When NOT to Use?”❌ Simple object creation
❌ Only one type ever created
❌ Trivial creation logic
❌ Performance is critical
Key Takeaways
Section titled “Key Takeaways”- Factory Pattern = Create objects without knowing exact class
- Factory = Centralized object creation
- Interface = Common contract for all products
- Benefit = Easy to extend, hard to break
- Principle = Open for extension, closed for modification
Common Pattern Structure
Section titled “Common Pattern Structure”# 1. Interfaceclass Product(ABC): @abstractmethod def do_something(self): pass
# 2. Concrete Productsclass ProductA(Product): ...class ProductB(Product): ...
# 3. Factoryclass Factory: @staticmethod def create(type: str) -> Product: # Creation logic here pass
# 4. Usageproduct = Factory.create("type_a")product.do_something()Remember
Section titled “Remember”- Factory Pattern simplifies object creation
- It decouples client from concrete classes
- It makes code more flexible and easier to extend
- Use it when creation is complex or you need flexibility
- Don’t use it for simple cases - avoid over-engineering!
Interview Focus: Factory Pattern
Section titled “Interview Focus: Factory Pattern”Key Points to Remember
Section titled “Key Points to Remember”1. Core Concept
Section titled “1. Core Concept”What to say:
“Factory Pattern is a creational design pattern that provides an interface for creating objects without specifying their exact classes. The factory decides which class to instantiate based on the input.”
Why it matters:
- Shows you understand the fundamental purpose
- Demonstrates knowledge of creational patterns category
- Indicates you can explain concepts clearly
2. When to Use Factory Pattern
Section titled “2. When to Use Factory Pattern”Must mention:
- ✅ Complex object creation - When initialization involves multiple steps
- ✅ Runtime type determination - When you don’t know the type until runtime
- ✅ Decoupling - When you want to separate creation from usage
- ✅ Extensibility - When you need to easily add new types
- ✅ Open/Closed Principle - When you want to extend without modifying
Example scenario to give:
“I’d use Factory Pattern when building a payment processing system where I need to support multiple payment gateways (Stripe, PayPal, Square). Each gateway has different initialization requirements, and I want to add new gateways without modifying existing code.”
3. Structure and Components
Section titled “3. Structure and Components”Must explain:
- Product Interface - Common interface for all products
- Concrete Products - Specific implementations
- Factory - Creates products based on input
- Client - Uses factory to get products
Visual explanation:
Client → Factory.create(type) → Returns Product → Concrete Implementation4. Benefits and Trade-offs
Section titled “4. Benefits and Trade-offs”Benefits to mention:
- Decoupling - Client doesn’t depend on concrete classes
- Flexibility - Easy to add new types
- Centralized Control - All creation logic in one place
- Testability - Easy to mock factories for testing
- Follows SOLID - Especially Open/Closed Principle
Trade-offs to acknowledge:
- Complexity - Adds abstraction layer (may be overkill for simple cases)
- Performance - Small overhead (usually negligible)
- Over-engineering risk - Don’t use for trivial cases
5. Common Interview Questions
Section titled “5. Common Interview Questions”Q: “What’s the difference between Factory Pattern and Factory Method Pattern?”
A:
“Factory Pattern (Simple Factory) uses a single method to create objects based on input. Factory Method Pattern is more advanced - each product has its own factory class. Factory Method provides more flexibility and follows the Open/Closed Principle better, but Simple Factory is often sufficient for most cases.”
Q: “When would you NOT use Factory Pattern?”
A:
“I wouldn’t use Factory Pattern when object creation is trivial - like creating a simple object with
new Class(). Also, if I only ever create one type of object, a factory is unnecessary. I’d avoid it if performance is critical and the overhead matters, though usually the overhead is negligible.”
Q: “How does Factory Pattern relate to SOLID principles?”
A:
“Factory Pattern primarily supports the Open/Closed Principle - you can add new product types without modifying existing code. It also supports Dependency Inversion Principle by making clients depend on abstractions (the interface) rather than concrete classes. Additionally, it can help with Single Responsibility Principle by separating creation logic from business logic.”
6. Implementation Details
Section titled “6. Implementation Details”Key implementation points:
-
Use Abstract Base Class (ABC) for the product interface
from abc import ABC, abstractmethodclass Product(ABC):@abstractmethoddef do_something(self): pass -
Factory method should return the interface type
def create(type: str) -> Product: # Return interface, not concrete class -
Handle error cases - Invalid types should raise exceptions
if not product_class:raise ValueError(f"Unknown type: {type}") -
Consider making factory static - If no state needed
@staticmethoddef create(type: str) -> Product:
7. Real-World Examples
Section titled “7. Real-World Examples”Good examples to mention:
- Payment Processing - Different payment gateways
- Database Connections - Different database types (MySQL, PostgreSQL)
- UI Components - Different button types (Windows, Mac, Linux)
- Logging Systems - Different log handlers (File, Console, Database)
- Notification Systems - Different channels (Email, SMS, Push)
8. Common Mistakes to Avoid
Section titled “8. Common Mistakes to Avoid”Mistakes interviewers watch for:
-
Over-engineering - Using Factory for simple cases
- ❌ Bad: Factory for creating simple objects
- ✅ Good: Factory for complex, multi-step creation
-
Returning inconsistent types - Factory should return interface type
- ❌ Bad: Returning different types (string, int, object)
- ✅ Good: Always return the interface type
-
Factory doing too much - Factory should only create, not validate/save/log
- ❌ Bad: Factory creates, validates, saves, and logs
- ✅ Good: Factory only creates and returns
-
Not handling errors - Should validate input and raise exceptions
- ❌ Bad: Returning None for invalid types
- ✅ Good: Raising ValueError with clear message
9. Comparison with Other Patterns
Section titled “9. Comparison with Other Patterns”Factory vs Builder:
- Factory - Creates objects of different types (Margherita vs Pepperoni pizza)
- Builder - Creates objects with complex construction (Pizza with many toppings)
Factory vs Singleton:
- Factory - Creates multiple instances of different types
- Singleton - Ensures only one instance exists
Factory vs Abstract Factory:
- Factory - Creates one type of product
- Abstract Factory - Creates families of related products
10. Code Quality Points
Section titled “10. Code Quality Points”What interviewers look for:
✅ Clean code - Readable, well-structured
✅ Type hints - Proper type annotations
✅ Error handling - Validates input, raises exceptions
✅ Documentation - Clear docstrings
✅ SOLID principles - Follows design principles
✅ Testability - Easy to test and mock
Example of good code:
Interview Checklist
Section titled “Interview Checklist”Before your interview, make sure you can:
- Define Factory Pattern clearly in one sentence
- Explain when to use it (with examples)
- Describe the structure and components
- List benefits and trade-offs
- Compare with other creational patterns
- Implement Factory Pattern from scratch
- Connect to SOLID principles
- Identify when NOT to use it
- Give 2-3 real-world examples
- Discuss common mistakes and how to avoid them
Interview Questions
Q1. What is the difference between Factory Method and Abstract Factory?
Q2. Does the Factory Pattern violate the Open/Closed Principle?
Q3. When should you avoid using the Factory Pattern?
new Class()) is sufficient. If the class structure is not expected to change or grow, adding a factory just introduces unnecessary complexity (over-engineering).Remember: Factory Pattern is about delegating object creation to a specialized factory, making your code more flexible and maintainable! 🏭