When building scalable and maintainable software systems, managing object creation properly becomes critical. Directly instantiating objects using the new keyword can tightly couple client code to concrete implementations, making systems harder to extend and maintain.
Factory patterns solve this problem by encapsulating object creation logic.
In this article, we’ll clearly understand:
- Simple Factory
- Factory Method
- Abstract Factory
With real-world examples in C#.
Why Do We Need Factory Patterns?
Consider a payment system that supports:
- UPI
- Credit Card
- Net Banking
If the client directly creates objects:
IPayment payment = new CreditCardPayment();
The client:
- Knows the concrete class
- Handles creation logic
- Becomes tightly coupled to implementation
If tomorrow a new payment type is introduced, client code must change.
This violates the Open/Closed Principle.
Factory patterns move object creation responsibility away from the client.
Simple Factory Pattern
What Is It?
Simple Factory centralizes object creation in one class using conditional logic (if/switch).
It is not an official GoF pattern but widely used in practice.
Real-World Example: E-commerce Checkout
User selects payment type at checkout.
Interface
public interface IPayment
{
void Process(decimal amount);
}
Implementations
public class UpiPayment : IPayment
{
public void Process(decimal amount)
=> Console.WriteLine("Processing UPI payment");
}
public class CardPayment : IPayment
{
public void Process(decimal amount)
=> Console.WriteLine("Processing Card payment");
}
Factory
public class PaymentFactory
{
public static IPayment Create(string type)
{
return type switch
{
"UPI" => new UpiPayment(),
"Card" => new CardPayment(),
_ => throw new ArgumentException("Invalid payment type")
};
}
}
Client
var payment = PaymentFactory.Create(userSelection);
payment.Process(1000);
Advantages
- Centralized object creation
- Reduces client coupling
- Easy to understand
Limitation
Adding a new payment type requires modifying the factory.
This partially violates Open/Closed Principle.
Best for small systems.
Factory Method Pattern
What Is It?
Factory Method defines an abstract method for creating objects. Subclasses decide which concrete implementation to instantiate.
Object creation is delegated to subclasses.
Real-World Example: Report Generation Framework
Suppose you’re building a reporting framework supporting:
- PDF reports
- Excel reports
Product Interface
public interface IReport
{
void Export();
}
Concrete Products
public class PdfReport : IReport
{
public void Export()
=> Console.WriteLine("Exporting PDF Report");
}
Abstract Creator
public abstract class ReportGenerator
{
public abstract IReport CreateReport();
public void Generate()
{
var report = CreateReport();
report.Export();
}
}
Concrete Creator
public class PdfReportGenerator : ReportGenerator
{
public override IReport CreateReport()
=> new PdfReport();
}
Why Is This Better?
- No switch-case
- Adding new report type requires creating a new subclass
- Better adherence to Open/Closed Principle
- Ideal for extensible frameworks
Abstract Factory Pattern
What Is It?
Abstract Factory provides an interface for creating families of related objects without specifying their concrete classes.
It creates multiple related objects together.
Real-World Example: Multi-Region SaaS Application
Suppose your product operates in:
- India
- USA
Each region requires:
- Payment service
- SMS service
India:
- Razorpay
- Local SMS Gateway
USA
- Stripe
- Twilio
These are related service families.
Abstract Products
public interface IPaymentService
{
void Pay();
}
public interface ISmsService
{
void SendSms();
}
Abstract Factory
public interface IServiceFactory
{
IPaymentService CreatePaymentService();
ISmsService CreateSmsService();
}
India Factory
public class IndiaServiceFactory : IServiceFactory
{
public IPaymentService CreatePaymentService()
=> new RazorpayPaymentService();
public ISmsService CreateSmsService()
=> new IndiaSmsService();
}
USA Factory
public class USServiceFactory : IServiceFactory
{
public IPaymentService CreatePaymentService()
=> new StripePaymentService();
public ISmsService CreateSmsService()
=> new TwilioSmsService();
}
Client Code
IServiceFactory factory = new IndiaServiceFactory();
var payment = factory.CreatePaymentService();
var sms = factory.CreateSmsService();
Why Use Abstract Factory?
- Ensures related objects are used together
- Clean separation of environments
- Ideal for multi-tenant, multi-region, enterprise systems
- Highly scalable architecture
| Pattern | Creation Control | Switch Used | Supports Families | OCP Compliance |
| Simple Factory | Central class | Yes | No | Partial |
| Factory Method | Subclasses | No | No | Good |
| Abstract Factory | Factory of factories | No | Yes | String |
When Should You Use Each?
Use Simple Factory when:
- System is small
- Limited object types
- Quick implementation needed
Use Factory Method when:
- Designing frameworks
- Expecting extensions
- Want subclass-based control
Use Abstract Factory when:
- Working with related object families
- Supporting multiple environments
- Building enterprise-level systems
Final Thoughts
Factory patterns are not about avoiding the new keyword.
They are about controlling object creation, reducing coupling, and designing extensible systems.
In modern .NET applications, Dependency Injection containers internally implement variations of Factory and Abstract Factory patterns.
Understanding when to use each pattern is what separates intermediate developers from senior engineers.
Thanks for reading









