The Factory Method pattern is a creational design pattern that defines an interface for creating an object but allows subclasses to alter the type of objects that will be created. It promotes loose coupling by delegating instantiation to subclasses.
Core Intent
“Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.”
This enables parallel class hierarchies and runtime polymorphism in object creation.
When to Use Factory Method
| Scenario | Use Case |
|---|---|
| A class cannot anticipate the type of objects to create | Future-proof design |
| Creation logic varies by subclass | e.g., OS-specific dialogs |
| Want to localize creation knowledge | In subclasses |
| Need parallel hierarchies | e.g., Document → PDFDocument, WordDocument |
| Extensibility is key | Add new types without changing core code |
Avoid when:
- Creation is simple → Use direct new
- No variation in product types → Use Simple Factory (not a GoF pattern)
Where It Is Used in Real Systems
| Domain | Example |
|---|---|
| UI Frameworks | Dialog creates WindowsButton or MacButton |
| Document Processing | Application.CreateDocument() → ExcelDocument, WordDocument |
| Game Engines | EnemyFactory.CreateEnemy(level) |
| ORMs | ConnectionFactory.CreateConnection(dbType) |
| Logging | LoggerFactory.CreateLogger(format) |
Key Benefits
- Open/Closed Principle: Add new product types without modifying existing code
- Decentralized creation: Each subclass knows its product
- Parallel hierarchies: Product and Creator evolve together
- Testability: Substitute mock creators
Real-World Example: E-Commerce Receipt Exporter System
An e-commerce platform needs to export order receipts in different formats depending on the context:
- Web → HTML (for browser/email)
- Reporting → PDF (for invoices)
- API Integration → JSON (for third-party systems)
Each context has its own factory that decides the export format.
C# Implementation
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json;
// ==================== PRODUCT INTERFACE ====================
public interface IReceiptExporter
{
string Export(OrderReceipt receipt);
string FileExtension { get; }
}
// ==================== CONCRETE PRODUCTS ====================
public class HtmlReceiptExporter : IReceiptExporter
{
public string Export(OrderReceipt receipt)
{
var sb = new StringBuilder();
sb.AppendLine("<!DOCTYPE html><html><body>");
sb.AppendLine($"<h2>Receipt - {receipt.StoreName}</h2>");
sb.AppendLine($"<p>Date: {receipt.OrderDate:yyyy-MM-dd}</p>");
sb.AppendLine($"<p>Customer: {receipt.CustomerName}</p>");
sb.AppendLine("<ul>");
foreach (var item in receipt.Items)
sb.AppendLine($"<li>{item.Name} x{item.Quantity} @ {item.UnitPrice:C} = {item.Subtotal:C}</li>");
sb.AppendLine("</ul>");
sb.AppendLine($"<p><strong>Total: {receipt.Total:C}</strong></p>");
sb.AppendLine("</body></html>");
return sb.ToString();
}
public string FileExtension => ".html";
}
public class PdfReceiptExporter : IReceiptExporter
{
public string Export(OrderReceipt receipt)
{
// Simulate PDF generation (in real use: iText, QuestPDF, etc.)
return $"[PDF Content for Order {receipt.OrderId} - Total: {receipt.Total:C}]";
}
public string FileExtension => ".pdf";
}
public class JsonReceiptExporter : IReceiptExporter
{
public string Export(OrderReceipt receipt)
{
return JsonSerializer.Serialize(receipt, new JsonSerializerOptions { WriteIndented = true });
}
public string FileExtension => ".json";
}
// ==================== ORDER RECEIPT (SIMPLE POCO) ====================
public class OrderReceipt
{
public string OrderId { get; set; }
public string StoreName { get; set; } = "GlobalMart";
public DateTime OrderDate { get; set; } = DateTime.Now;
public string CustomerName { get; set; }
public List<OrderItem> Items { get; set; } = new();
public decimal Tax { get; set; }
public decimal Shipping { get; set; }
public decimal Total => Items.Sum(i => i.Subtotal) + Tax + Shipping;
}
public class OrderItem
{
public string Name { get; set; }
public int Quantity { get; set; }
public decimal UnitPrice { get; set; }
public decimal Subtotal => Quantity * UnitPrice;
}
// ==================== CREATOR (ABSTRACT) ====================
public abstract class ReceiptExporterFactory
{
// Factory Method — subclasses override
public abstract IReceiptExporter CreateExporter();
// Template method: common export flow
public string ExportReceipt(OrderReceipt receipt)
{
var exporter = CreateExporter();
var content = exporter.Export(receipt);
var filename = $"receipt_{receipt.OrderId}{exporter.FileExtension}";
Console.WriteLine($"[Factory] Exporting using {GetType().Name} → {filename}");
// In real app: save to file, send email, etc.
return content;
}
}
// ==================== CONCRETE CREATORS ====================
public class WebReceiptExporterFactory : ReceiptExporterFactory
{
public override IReceiptExporter CreateExporter() => new HtmlReceiptExporter();
}
public class ReportReceiptExporterFactory : ReceiptExporterFactory
{
public override IReceiptExporter CreateExporter() => new PdfReceiptExporter();
}
public class ApiReceiptExporterFactory : ReceiptExporterFactory
{
public override IReceiptExporter CreateExporter() => new JsonReceiptExporter();
}
// ==================== CLIENT / DEMO ====================
class Program
{
static void Main()
{
var receipt = new OrderReceipt
{
OrderId = "ORD-2025",
CustomerName = "Bob Smith",
Items = new List<OrderItem>
{
new() { Name = "Laptop", Quantity = 1, UnitPrice = 1200.00m },
new() { Name = "Mouse", Quantity = 1, UnitPrice = 25.00m }
},
Tax = 98.75m,
Shipping = 15.00m
};
Console.WriteLine("=== FACTORY METHOD IN E-COMMERCE ===\n");
// Client uses different factories based on context
ReceiptExporterFactory factory;
// 1. Web context → HTML
factory = new WebReceiptExporterFactory();
Console.WriteLine(factory.ExportReceipt(receipt));
Console.WriteLine();
// 2. Reporting context → PDF
factory = new ReportReceiptExporterFactory();
Console.WriteLine(factory.ExportReceipt(receipt));
Console.WriteLine();
// 3. API context → JSON
factory = new ApiReceiptExporterFactory();
var json = factory.ExportReceipt(receipt);
Console.WriteLine(json);
}
}Sample Output
=== FACTORY METHOD IN E-COMMERCE ===
[Factory] Exporting using WebReceiptExporterFactory → receipt_ORD-2025.html
<!DOCTYPE html><html><body>
<h2>Receipt - GlobalMart</h2>
<p>Date: 2025-04-05</p>
<p>Customer: Bob Smith</p>
<ul>
<li>Laptop x1 @ $1,200.00 = $1,200.00</li>
...
[Factory] Exporting using ReportReceiptExporterFactory → receipt_ORD-2025.pdf
[PDF Content for Order ORD-2025 - Total: $1,338.75]
[Factory] Exporting using ApiReceiptExporterFactory → receipt_ORD-2025.json
{
"OrderId": "ORD-2025",
"StoreName": "GlobalMart",
...
}UML Class Diagram

Participants in the Factory Method Pattern
The classes and objects participating in this pattern include:
- Product (IReceiptExporter)
- Defines the interface of objects the factory method creates.
- ConcreteProduct (HtmlReceiptExporter, PdfReceiptExporter, JsonReceiptExporter)
- Implements the Product interface.
- Represents the actual object being created.
- Creator (ReceiptExporterFactory)
- Declares the factory method, which returns a Product object.
- May provide a default implementation.
- ConcreteCreator (WebReceiptExporterFactory, ReportReceiptExporterFactory, ApiReceiptExporterFactory)
- Overrides the factory method to return a specific ConcreteProduct.
- Client
- Uses the Creator interface.
- Calls CreateExporter() without knowing the concrete type.
Summary Table
| Participant | Role in E-Commerce Example |
|---|---|
| Product | IReceiptExporter – export contract |
| ConcreteProduct | HtmlReceiptExporter, PdfReceiptExporter, JsonReceiptExporter |
| Creator | ReceiptExporterFactory – declares CreateExporter() |
| ConcreteCreator | WebReceiptExporterFactory, etc. – override to return specific exporter |
| Client | Program – selects factory based on use case |
Advantages in E-Commerce
| Benefit | Impact |
|---|---|
| Extensible | Add XmlReceiptExporterFactory → no core changes |
| Decoupled | Client doesn’t know export format |
| Parallel Hierarchies | Web → HTML, API → JSON |
| Template Method | ExportReceipt() provides common flow |
Factory Method vs Abstract Factory
| Aspect | Factory Method | Abstract Factory |
|---|---|---|
| Creates | One product | Family of products |
| Extensibility | Add new creator + product | Add new factory |
| Use Case | Single varying object | Group of related objects |
| Example | CreateLogger() | CreateUIComponents() |
Conclusion
The Factory Method pattern is ideal when creation logic varies by context and you want subclasses to own instantiation. In e-commerce, it enables clean separation of export formats (HTML, PDF, JSON) while allowing new formats to be added seamlessly.




