
What is the Factory Pattern?
The Factory Pattern is like ordering food at a restaurant. You don’t go into the kitchen and cook your meal yourself – you simply tell the waiter what you want, and the kitchen creates it for you. You get your food without needing to know the recipe, ingredients, or cooking techniques. That’s exactly what the Factory Pattern does in programming.
In technical terms, the Factory Pattern is a creational design pattern that provides an interface for creating objects without specifying their exact classes. It delegates the instantiation logic to specialized factory classes or methods, keeping your code flexible and maintainable.
The Restaurant Analogy
Let’s expand on the restaurant analogy to really understand this pattern:
Imagine you walk into a restaurant and order “a vegetarian meal.” The waiter doesn’t bring you ingredients and a recipe – they bring you a complete, ready-to-eat dish. Behind the scenes, the kitchen (factory) decided whether to make you pasta, a salad, or a veggie burger based on the restaurant’s menu and your request.
The key benefits here:
- You don’t need to know how to cook
- You don’t need to know what ingredients are available
- The restaurant can change recipes without you noticing
- You just get what you asked for
Types of Factory Patterns
There are three variations of the Factory Pattern, each serving different needs:
graph LR A[Factory Patterns] A --> B[Simple Factory] B --> B1[Single factory class creates objects] B --> B2[Not a formal pattern but widely used] A --> C[Factory Method] C --> C1[Defines interface for creation] C --> C2[Subclasses decide what to create] A --> D[Abstract Factory] D --> D1[Creates families of related objects] D --> D2[Factory of factories] style A fill:#4a90e2,color:#fff style B fill:#7cb342,color:#fff style C fill:#fb8c00,color:#fff style D fill:#ab47bc,color:#fff
Simple Factory (Factory Pattern)
The Simple Factory is the most straightforward version. Think of it as a vending machine – you press a button (pass a parameter), and it gives you the product you requested.
Structure
classDiagram class Product { <> +operation() } class ConcreteProductA { +operation() } class ConcreteProductB { +operation() } class SimpleFactory { +createProduct(type) } class Client { +useProduct() } Product <|.. ConcreteProductA Product <|.. ConcreteProductB SimpleFactory ..> Product: creates Client --> SimpleFactory: uses Client --> Product: uses
How It Works
The Simple Factory has a single method that creates objects based on input parameters. It centralizes the creation logic in one place.
Pseudo Code
// Product Interface
interface Vehicle:
method drive()
method getType()
// Concrete Products
class Car implements Vehicle:
method drive():
print "Driving a car on the road"
method getType():
return "Car"
class Motorcycle implements Vehicle:
method drive():
print "Riding a motorcycle"
method getType():
return "Motorcycle"
class Truck implements Vehicle:
method drive():
print "Driving a heavy truck"
method getType():
return "Truck"
// Simple Factory
class VehicleFactory:
method createVehicle(type):
if type == "car":
return new Car()
else if type == "motorcycle":
return new Motorcycle()
else if type == "truck":
return new Truck()
else:
throw Error("Unknown vehicle type")
// Client Usage
factory = new VehicleFactory()
vehicle = factory.createVehicle("car")
vehicle.drive()
Real-World Use Cases
- Document Generators: Creating different document types (PDF, Word, Excel) based on user selection
- Payment Processing: Creating payment handlers (Credit Card, PayPal, Stripe) based on user choice
- Logging Systems: Creating different loggers (File, Database, Console) based on configuration
- Image Processors: Creating handlers for different image formats (JPEG, PNG, GIF)
Factory Method Pattern
The Factory Method is more sophisticated. Imagine a franchise restaurant – each location has its own kitchen (factory method) that follows the company’s recipe guidelines but can customize dishes for local tastes. The interface is the same, but each location decides exactly what to create.
The Key Difference
Unlike Simple Factory where one class creates everything, Factory Method lets subclasses decide what to create. It defines an interface for creation but lets child classes choose which class to instantiate.
Structure
classDiagram class Creator { <> +factoryMethod() +someOperation() } class ConcreteCreatorA { +factoryMethod() } class ConcreteCreatorB { +factoryMethod() } class Product { <> +operation() } class ConcreteProductA { +operation() } class ConcreteProductB { +operation() } Creator <|-- ConcreteCreatorA Creator <|-- ConcreteCreatorB Product <|.. ConcreteProductA Product <|.. ConcreteProductB ConcreteCreatorA ..> ConcreteProductA: creates ConcreteCreatorB ..> ConcreteProductB: creates Creator ..> Product: uses
Flow Diagram
sequenceDiagram participant Client participant Creator participant ConcreteCreator participant Product Client->>ConcreteCreator: someOperation() ConcreteCreator->>ConcreteCreator: factoryMethod() ConcreteCreator->>Product: create instance Product-->>ConcreteCreator: return product ConcreteCreator->>Product: use product ConcreteCreator-->>Client: return result
Pseudo Code
// Product Interface
interface Notification:
method send(message)
// Concrete Products
class EmailNotification implements Notification:
method send(message):
print "Sending email: " + message
class SMSNotification implements Notification:
method send(message):
print "Sending SMS: " + message
class PushNotification implements Notification:
method send(message):
print "Sending push notification: " + message
// Creator (Abstract Class)
abstract class NotificationService:
// Factory Method - to be implemented by subclasses
abstract method createNotification(): Notification
// Business logic using the factory method
method notify(message):
notification = this.createNotification()
notification.send(message)
// Concrete Creators
class EmailNotificationService extends NotificationService:
method createNotification():
return new EmailNotification()
class SMSNotificationService extends NotificationService:
method createNotification():
return new SMSNotification()
class PushNotificationService extends NotificationService:
method createNotification():
return new PushNotification()
// Client Usage
service = new EmailNotificationService()
service.notify("Hello from Factory Method!")
// Can easily switch to different notification type
smsService = new SMSNotificationService()
smsService.notify("Hello via SMS!")
Real-World Use Cases
- UI Frameworks: Creating platform-specific UI components (Windows buttons vs Mac buttons)
- Database Connections: Creating different database connectors (MySQL, PostgreSQL, MongoDB)
- Export Functions: Creating different exporters in applications (PDF exporter, Excel exporter)
- Game Development: Creating different enemy types based on game level or difficulty
- Plugin Systems: Loading and creating different plugin implementations dynamically
When to Use Factory Pattern
flowchart TD A[Need to create objects?] --> B{Know exact type at compile time?} B -->|Yes| C[Direct instantiation is fine] B -->|No| D{Creation logic complex?} D -->|No| E{Multiple related types?} D -->|Yes| F[Use Factory Pattern] E -->|No| C E -->|Yes| F F --> G{Need subclass flexibility?} G -->|Yes| H[Use Factory Method] G -->|No| I[Use Simple Factory] style F fill:#c8e6c9 style H fill:#c8e6c9 style I fill:#c8e6c9 style C fill:#ffcdd2
Consider using the Factory Pattern when:
- You don’t know beforehand the exact types of objects your code will work with
- You want to provide a library where users can extend internal components
- You want to save system resources by reusing existing objects instead of rebuilding them
- Object creation involves complex logic that shouldn’t be repeated
- You need to decouple object creation from usage
Real-World Scenario: Notification System
Let’s walk through a practical example – building a notification system for an e-commerce application.
The Problem
Your e-commerce platform needs to send notifications through multiple channels:
- Email for order confirmations
- SMS for delivery updates
- Push notifications for promotional offers
- In-app messages for account updates
Without Factory Pattern, you might write something like this everywhere:
// Bad approach - repeated logic everywhere
if notificationType == "email":
notification = new EmailNotification()
notification.setServer(emailServer)
notification.setCredentials(credentials)
else if notificationType == "sms":
notification = new SMSNotification()
notification.setProvider(smsProvider)
notification.setApiKey(apiKey)
// ... and so on
The Solution with Factory Pattern
// Factory handles all the complexity
class NotificationFactory:
method createNotification(type, config):
switch type:
case "email":
notification = new EmailNotification()
notification.configure(config.emailSettings)
return notification
case "sms":
notification = new SMSNotification()
notification.configure(config.smsSettings)
return notification
case "push":
notification = new PushNotification()
notification.configure(config.pushSettings)
return notification
default:
throw Error("Unknown notification type")
// Client code is now clean and simple
factory = new NotificationFactory()
notification = factory.createNotification("email", config)
notification.send("Your order has been confirmed!")
Benefits in This Scenario
- Centralized Logic: All notification creation logic is in one place
- Easy to Extend: Adding WhatsApp notifications? Just add one case in the factory
- Easy to Test: Mock the factory to test different notification scenarios
- Clean Client Code: The rest of your code doesn’t need to know implementation details
Benefits of Factory Pattern
- Loose Coupling: Client code doesn’t depend on concrete classes, only interfaces
- Single Responsibility: Creation logic is separated from business logic
- Open/Closed Principle: Easy to add new product types without modifying existing code
- Easier Testing: Can easily mock or stub objects in tests
- Code Reusability: Factory logic is reused across the application
- Flexibility: Can change what gets created without affecting client code
Potential Drawbacks
- Increased Complexity: Adds more classes and interfaces to your codebase
- Indirection: Extra layer between client and concrete classes can make code harder to follow
- Overhead: May be overkill for simple object creation scenarios
- Learning Curve: Team members need to understand the pattern to maintain code effectively
Factory Pattern vs Direct Instantiation
Here’s when to use each approach:
Scenario | Direct Instantiation | Factory Pattern |
---|---|---|
Simple object creation | ✓ Use this | Overkill |
Type known at compile time | ✓ Use this | Not needed |
Complex creation logic | Avoid | ✓ Use this |
Type determined at runtime | Difficult | ✓ Use this |
Multiple related types | Messy | ✓ Use this |
Need to extend types | Hard to maintain | ✓ Use this |
Common Mistakes to Avoid
- Overusing the Pattern: Don’t make everything a factory. Simple object creation doesn’t need it.
- God Factory: Avoid creating one giant factory that creates every type in your system. Keep factories focused.
- Ignoring Error Handling: Always handle cases where the requested type doesn’t exist.
- Tight Coupling in Factory: The factory itself shouldn’t have too many dependencies.
- Not Using Interfaces: Products should implement common interfaces for true flexibility.
Best Practices
- Return Interfaces, Not Concrete Classes: Factory methods should return interface types
- Keep Factories Simple: Don’t add business logic to factories – they should only create objects
- Use Dependency Injection: Pass configuration to factories rather than hardcoding
- Consider Registration: For extensible systems, let products register themselves with the factory
- Document Type Parameters: Clearly document what types the factory can create
- Thread Safety: Consider thread safety if factories are used in multi-threaded environments
Combining with Other Patterns
Factory Pattern works well with other design patterns:
- Singleton + Factory: Make the factory itself a singleton to ensure consistent object creation
- Prototype + Factory: Factory can clone prototypes instead of creating from scratch
- Strategy + Factory: Factory creates different strategy implementations
- Dependency Injection + Factory: Inject factories to provide flexible object creation
Decision Guide
flowchart TD A[Need object creation abstraction?] --> B{Simple or Complex?} B -->|Simple| C{Few types?} B -->|Complex| D[Use Factory Method] C -->|Yes, 2-5 types| E[Use Simple Factory] C -->|No, many types| F{Need families?} F -->|Yes| G[Consider Abstract Factory] F -->|No| D style E fill:#c8e6c9 style D fill:#c8e6c9 style G fill:#fff9c4
Key Takeaways
- Factory Pattern provides a way to create objects without specifying exact classes
- Simple Factory centralizes creation logic in one class
- Factory Method delegates creation decisions to subclasses
- Use it when you need flexibility in what gets created
- It promotes loose coupling and follows SOLID principles
- Don’t overuse it for simple scenarios where direct instantiation works fine
- Real-world applications: payment systems, notification services, document generators, plugin architectures
The Factory Pattern is one of the most widely used design patterns in software development. Understanding when and how to apply it will significantly improve your code’s flexibility and maintainability. In the next post, we’ll explore actual code implementations across different programming languages.