Introduction
The Factory Pattern is a creational design pattern that provides an interface for creating objects while allowing subclasses or a centralized factory to decide which concrete class to instantiate. It promotes loose coupling by eliminating direct object creation using the new keyword in client code.
Problem Statement
When an application directly creates objects using concrete classes, it becomes tightly coupled to those implementations. This makes the system hard to extend, test, and maintain, especially when new object types are introduced.
Solution
The Factory Pattern encapsulates object creation logic in a separate factory class or method. The client requests an object from the factory by providing some input, and the factory returns the appropriate concrete implementation.
Key Benefits
Reduces tight coupling between client and concrete classes
Centralizes object creation logic
Improves maintainability and scalability
Supports Open Closed Principle
Types of Factory Pattern
Simple Factory
Factory Method
Abstract Factory
This article focuses on the Simple Factory pattern, which is widely used in real-world applications.
Example Scenario
Assume we are building a notification system that can send Email, SMS, or Push notifications. The client should not know which concrete class is being instantiated.
Step 1 Define the Product Interface
public interface INotification
{
void Send(string message);
}
Step 2 Create Concrete Products
public class EmailNotification : INotification
{
public void Send(string message)
{
Console.WriteLine("Email sent: " + message);
}
}
public class SmsNotification : INotification
{
public void Send(string message)
{
Console.WriteLine("SMS sent: " + message);
}
}
public class PushNotification : INotification
{
public void Send(string message)
{
Console.WriteLine("Push notification sent: " + message);
}
}
Step 3 Create the Factory Class
public static class NotificationFactory
{
public static INotification Create(string type)
{
return type.ToLower() switch
{
"email" => new EmailNotification(),
"sms" => new SmsNotification(),
"push" => new PushNotification(),
_ => throw new ArgumentException("Invalid notification type")
};
}
}
Step 4 Client Usage
class Program
{
static void Main()
{
INotification notification = NotificationFactory.Create("email");
notification.Send("Factory Pattern in action");
}
}
How It Works
The client calls the factory instead of instantiating concrete classes directly. The factory evaluates the input and returns the correct implementation of the interface. The client only depends on the abstraction, not the concrete types.
When to Use Factory Pattern
When object creation logic is complex
When the exact type of object is determined at runtime
When you want to decouple object creation from usage
When adding new types should not affect client code
Common Mistakes
Overusing factory for simple object creation
Adding too much logic inside the factory
Violating single responsibility by mixing business logic in factory
Real World Usage
Dependency Injection containers internally use factory concepts
ORM frameworks create database providers using factories
Logging frameworks instantiate loggers based on configuration
Conclusion
The Factory Pattern is a foundational design pattern that helps build flexible and maintainable systems. By centralizing object creation and programming to interfaces, applications become easier to extend and test without modifying existing client code.