What is the Factory pattern, and when would you use it?

SOLID & Design Patterns Patterns Intermediate 2–3 Yrs3–5 Yrs Architecture 2 min read

Quick Answer

A Factory centralises object creation so callers ask for what they need, not how to build it. Use it when construction is complex, depends on runtime data, or you must choose an implementation dynamically — e.g. return a PdfExporter or CsvExporter based on a requested format.

A Factory hides object creation behind a method so the caller just asks for what it wants. I use it when building the object is complicated, or when I need to pick the implementation at runtime — like returning a PDF exporter or a CSV exporter based on what the user asked for. There's the simple factory with a switch, the Factory Method where subclasses choose the type, and the Abstract Factory for creating a family of related objects. In .NET the DI container often plays the factory role, but I'll write an explicit factory when the decision depends on runtime data or I need to spin up lots of short-lived instances with per-call parameters.

  • Simple factory — a method (ExporterFactory.Create(format)) with a switch that returns the right type behind a common interface.
  • Factory Method — a base class declares an abstract CreateProduct() and subclasses decide the concrete type.
  • Abstract Factory — a factory that creates a family of related objects (a whole UI theme's widgets).

In modern .NET, the DI container is often the factory — register the implementations and inject IEnumerable<IExporter> or a keyed service. Explicit factories still shine when the choice depends on runtime input, when you need to create many short-lived instances, or when construction needs parameters not known at registration time (Func<T> or a typed factory).

C# — simple factory
public interface IExporter { byte[] Export(Report r); }

public class ExporterFactory
{
    private readonly IServiceProvider _sp;
    public ExporterFactory(IServiceProvider sp) => _sp = sp;

    public IExporter Create(string format) => format.ToLower() switch
    {
        "pdf" => _sp.GetRequiredService<PdfExporter>(),
        "csv" => _sp.GetRequiredService<CsvExporter>(),
        _     => throw new NotSupportedException($"format {format}")
    };
}