Factory Pattern

Learn how the Factory Pattern enables flexible object creation without binding your code to specific classes. Includes C# and Python examples, UML, and real-world use cases.

Design Patterns in Practice: Mastering the Factory Pattern

Create Objects Without Binding to Specific Classes


1. Why Object Creation Deserves Its Own Pattern

In small apps, creating objects using new works fine. But as systems scale and vary by configuration, hardcoding instantiation leads to:

  • Tight coupling to specific classes
  • Duplicated logic scattered across the codebase
  • Rigid structures that make extensions risky

The Factory Pattern solves this by centralizing and abstracting object creation.

2. What Is the Factory Pattern?

The Factory Pattern is a Creational Design Pattern that provides a method to create objects, letting the code decide which class to instantiate at runtime — based on input or configuration.

Instead of:

var export = new PdfExporter();

You do:

var export = ExportFactory.Create("pdf");

This enables the Open/Closed Principle: easily add new types without changing the calling code.

3. Real-World Analogy

Think of a car factory. You don’t build each car manually. You specify what you want — the factory handles the details and gives you the right car model. The Factory Pattern does the same for objects in code.

4. Factory Pattern UML (Conceptual)

5. A Real Use Case: Export System

Step 1: Define the Interface

public interface IExporter {
    void Export(string data);
}

Step 2: Implement Concrete Exporters

public class PdfExporter : IExporter {
    public void Export(string data) =>
        Console.WriteLine($"Exporting to PDF: {data}");
}

public class CsvExporter : IExporter {
    public void Export(string data) =>
        Console.WriteLine($"Exporting to CSV: {data}");
}

Step 3: Create the ExportFactory

public static class ExportFactory {
    public static IExporter Create(string type) {
        return type.ToLower() switch {
            "pdf" => new PdfExporter(),
            "csv" => new CsvExporter(),
            _ => throw new ArgumentException("Invalid export type")
        };
    }
}

Step 4: Use It

class Program {
    static void Main() {
        var exporter = ExportFactory.Create("csv");
        exporter.Export("Report data");
    }
}

6. Real-Life Applications

  • Notification Services
  • Shape Drawing Tools
  • File Export Utilities
  • Dynamic Payment Gateways

7. Benefits

  • ✅ Decouples object creation from logic
  • ✅ Centralized creation logic
  • ✅ Test-friendly structure
  • ✅ Easy to extend

8. Drawbacks & Caveats

  • ⚠️ Extra boilerplate for simple cases
  • ⚠️ Can hide actual class from the reader
  • ⚠️ Potential overuse in small apps

9. Factory Pattern Variants

  • Simple Factory: Static method to create products
  • Factory Method: Subclass decides what to instantiate
  • Abstract Factory: Creates families of related objects

Factory Pattern Variants: Simple Factory, Factory Method, and Abstract Factory

Simple Factory Pattern (Unofficial)

The Simple Factory is not a formal design pattern but a common utility that provides a static method to create objects based on input parameters. It centralizes object creation without the complexity of full factory patterns.

Example:


public interface IExporter
{
    void Export(string data);
}

public class PdfExporter : IExporter
{
    public void Export(string data) => Console.WriteLine($"PDF: {data}");
}

public class CsvExporter : IExporter
{
    public void Export(string data) => Console.WriteLine($"CSV: {data}");
}

public static class SimpleExportFactory
{
    public static IExporter Create(string type)
    {
        return type.ToLower() switch
        {
            "pdf" => new PdfExporter(),
            "csv" => new CsvExporter(),
            _ => throw new ArgumentException("Invalid type")
        };
    }
}

// Usage
var exporter = SimpleExportFactory.Create("pdf");
exporter.Export("Simple report");
    

Factory Method Pattern

The Factory Method Pattern defines an interface for creating objects but lets subclasses alter the type of objects that will be created. It promotes loose coupling by allowing the client code to work with interfaces rather than concrete classes.

Example:


public interface IShape
{
    void Draw();
}

public class Circle : IShape
{
    public void Draw() => Console.WriteLine("Drawing Circle");
}

public class Square : IShape
{
    public void Draw() => Console.WriteLine("Drawing Square");
}

public abstract class ShapeCreator
{
    public abstract IShape CreateShape();
}

public class CircleCreator : ShapeCreator
{
    public override IShape CreateShape() => new Circle();
}

public class SquareCreator : ShapeCreator
{
    public override IShape CreateShape() => new Square();
}

// Usage
ShapeCreator creator = new CircleCreator();
IShape shape = creator.CreateShape();
shape.Draw();
    

Abstract Factory Pattern

The Abstract Factory Pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes. It is useful when the system needs to be independent of how its objects are created, composed, and represented.

Example:


// Product Interfaces
public interface IButton { void Render(); }
public interface ITextBox { void Render(); }

// Concrete Products
public class LightButton : IButton
{
    public void Render() => Console.WriteLine("Light Button");
}
public class DarkButton : IButton
{
    public void Render() => Console.WriteLine("Dark Button");
}

public class LightTextBox : ITextBox
{
    public void Render() => Console.WriteLine("Light TextBox");
}
public class DarkTextBox : ITextBox
{
    public void Render() => Console.WriteLine("Dark TextBox");
}

// Abstract Factory
public interface IWidgetFactory
{
    IButton CreateButton();
    ITextBox CreateTextBox();
}

// Concrete Factories
public class LightThemeFactory : IWidgetFactory
{
    public IButton CreateButton() => new LightButton();
    public ITextBox CreateTextBox() => new LightTextBox();
}

public class DarkThemeFactory : IWidgetFactory
{
    public IButton CreateButton() => new DarkButton();
    public ITextBox CreateTextBox() => new DarkTextBox();
}

// Client
public class UIBuilder
{
    private readonly IWidgetFactory _factory;
    public UIBuilder(IWidgetFactory factory)
    {
        _factory = factory;
    }

    public void RenderUI()
    {
        var button = _factory.CreateButton();
        var textBox = _factory.CreateTextBox();
        button.Render();
        textBox.Render();
    }
}

// Usage
var builder = new UIBuilder(new LightThemeFactory());
builder.RenderUI();
    

Comparison Table

Feature Simple Factory Factory Method Abstract Factory
Pattern Type Utility / Static Inheritance-based Family of objects
Flexibility Low Medium High
Complexity Low Medium High
Common Use Single type decision Custom subclass logic UI kits, theming systems

10. Conclusion

Understanding different factory patterns helps you write scalable and maintainable software. Each has its place — from simple decision-making to complex family creation. Choose based on the problem, not the pattern’s popularity.

🔜 Next Up: Singleton Pattern – Global Access Without Global Mess

11. Related Blogs