Factory Design Pattern — Digitteck
Factory Design Pattern
dotnet·8 July 2018·4 min read

Factory Design Pattern

The factory design pattern is a creational pattern that decouples object construction from the class that uses the object. Rather than instantiating concrete types with new scattered through the code, a factory method centralises construction — making it easy to swap, extend, or test without touching the consuming code.

When to apply it: the target object needs to be extended to sub-classes; the base class should not be aware of its concrete sub-classes; or the product implementation is expected to change over time.

Without Factory Pattern

A classic OOP approach defines the model hierarchy and a factory class that switches on the type enum to return the correct instance. Adding a new model means touching the switch statement here — and in every similar switch throughout the codebase:

csharp
// Base car class — all Audi models inherit this
public abstract class AudiCar
{
    public AudiModels CarType { get; }
    public AudiCar(AudiModels carType) => CarType = carType;
    public override string ToString() => CarType.ToString();
}

public enum AudiModels { AudiEPhaeton, AudiA, AudiC }

public class AudiModelA       : AudiCar { public AudiModelA()       : base(AudiModels.AudiA)       {} }
public class AudiModelC       : AudiCar { public AudiModelC()       : base(AudiModels.AudiC)       {} }
public class AudiModelEPhaeton: AudiCar { public AudiModelEPhaeton(): base(AudiModels.AudiEPhaeton) {} }
csharp
// Classic factory — every new model requires editing this switch statement
// and every other switch statement like it scattered across the codebase
public class AudiFactory
{
    public AudiCar Buy(AudiModels audiCarType)
    {
        switch (audiCarType)
        {
            case AudiModels.AudiA:        return new AudiModelA();
            case AudiModels.AudiC:        return new AudiModelC();
            case AudiModels.AudiEPhaeton: return new AudiModelEPhaeton();
            default: return null;
        }
    }
}

Factory Design Pattern

Introduce an IAudiSpecs interface that mandates a factory method. Each model gets its own specs class that implements the method. The factory only knows the interface — adding a model is a new class, not an edit:

csharp
// The base class stays the same.
// Add an interface that forces each model to supply its own factory method.
public interface IAudiSpecs
{
    AudiCar CreateCar();
}

// Each model's specs class implements the factory method in isolation —
// adding a new model means adding a new class, not editing existing ones.
public class AudiASpecs : IAudiSpecs
{
    public AudiCar CreateCar() => new AudiA();
}

public class AudiEPhaetonSpecs : IAudiSpecs
{
    public AudiCar CreateCar() => new AudiModelEPhaeton();
}

// The factory interface works on IAudiSpecs, never on concrete model types.
public interface IAudiFactory
{
    string Location { get; }
    AudiCar CreateCar(IAudiSpecs audiSpecs);
}

// Location-specific factories — each delegates creation to the specs object.
public class AudiNewYorkFactory : IAudiFactory
{
    public string Location => "NewYork";
    public AudiCar CreateCar(IAudiSpecs audiSpecs) => audiSpecs.CreateCar();
}

public class AudiSingaporeFactory : IAudiFactory
{
    public string Location => "Singapore";
    public AudiCar CreateCar(IAudiSpecs audiSpecs) => audiSpecs.CreateCar();
}

// Usage: the caller selects factory + specs; no switch statements needed.
AudiNewYorkFactory factory = new AudiNewYorkFactory();
AudiCar car = factory.CreateCar(new AudiASpecs());

Abstract Factory

An abstract builder combines a factory with a specific model, giving callers a single entry point. The trade-off is one class per factory/model combination, but each class is small and change is non-invasive — adding a new combination requires only a new class:

csharp
// Abstract builder couples a factory to a specific model.
// New combinations require only a new class — nothing else changes.
public abstract class AudiAbstractBuilder
{
    protected IAudiFactory AudiFactory;
    public AudiAbstractBuilder(IAudiFactory factory) => AudiFactory = factory;
    public abstract AudiCar OrderCar();
}

// NY factory producing only model E
public class AudiEPhaetonNYBuilder : AudiAbstractBuilder
{
    public AudiEPhaetonNYBuilder() : base(new AudiNewYorkFactory()) {}
    public override AudiCar OrderCar() => AudiFactory.CreateCar(new AudiEPhaetonSpecs());
}

// Singapore factory producing model E
public class AudiEPhaetonSBuilder : AudiAbstractBuilder
{
    public AudiEPhaetonSBuilder() : base(new AudiSingaporeFactory()) {}
    public override AudiCar OrderCar() => AudiFactory.CreateCar(new AudiEPhaetonSpecs());
}

// Usage
AudiAbstractBuilder builder = new AudiEPhaetonNYBuilder();
AudiCar audiCar = builder.OrderCar();

Tags

C#.NETDesign PatternsFactory
digitteck

© 2026 Digitteck