Factory Method Pattern
Definitionβ
The Factory Method defines an interface for creating objects, but lets subclasses decide which class to instantiate. The method defers instantiation to derived classes, decoupling client code from concrete types.
Coffee Shop Exampleβ
A coffee shop takes orders from different channels β walk-in customers, a mobile app, and a drive-through. Each channel creates coffee differently (different defaults, sizes, extras), but the ordering process is the same.
Structureβ
Implementationβ
// The Creator abstract class
public abstract class CoffeeOrderBase
{
// Factory Method β subclasses decide what to create
public abstract Coffee CreateCoffee();
// Template method β shared logic that uses the factory method
public string PlaceOrder()
{
var coffee = CreateCoffee();
return $"Order placed: {coffee}";
}
}
// Concrete Creators β each creates a different coffee
public class WalkInOrder : CoffeeOrderBase
{
public override Coffee CreateCoffee() => new Espresso();
}
public class MobileAppOrder : CoffeeOrderBase
{
public override Coffee CreateCoffee() => new Latte { Size = CupSize.Large };
}
public class DriveThroughOrder : CoffeeOrderBase
{
public override Coffee CreateCoffee() => new Cappuccino();
}
// Usage
CoffeeOrderBase order = new MobileAppOrder();
Console.WriteLine(order.PlaceOrder());
// Output: Order placed: Latte (Large) β $4.00 [Espresso Shot, Steamed Milk]
With Parameters β Choosing Coffee Type at Runtimeβ
public enum CoffeeType { Espresso, Latte, Cappuccino }
public class SmartCoffeeOrder : CoffeeOrderBase
{
private readonly CoffeeType _type;
private readonly CupSize _size;
public SmartCoffeeOrder(CoffeeType type, CupSize size = CupSize.Medium)
{
_type = type;
_size = size;
}
public override Coffee CreateCoffee() => _type switch
{
CoffeeType.Espresso => new Espresso { Size = _size },
CoffeeType.Latte => new Latte { Size = _size },
CoffeeType.Cappuccino => new Cappuccino { Size = _size },
_ => throw new ArgumentException($"Unknown coffee type: {_type}")
};
}
// Usage
var order = new SmartCoffeeOrder(CoffeeType.Latte, CupSize.Large);
Console.WriteLine(order.PlaceOrder());
// Output: Order placed: Latte (Large) β $4.00 [Espresso Shot, Steamed Milk]
Simple Factory (Not a GoF Pattern, But Common)β
A Simple Factory is a single class with one method that creates objects based on a parameter. It's not a true GoF pattern but is widely used when you don't need subclass-based flexibility.
public static class CoffeeFactory
{
public static Coffee Create(CoffeeType type, CupSize size = CupSize.Medium) => type switch
{
CoffeeType.Espresso => new Espresso { Size = size },
CoffeeType.Latte => new Latte { Size = size },
CoffeeType.Cappuccino => new Cappuccino { Size = size },
_ => throw new ArgumentException($"Unknown coffee type: {type}")
};
}
// Usage
var coffee = CoffeeFactory.Create(CoffeeType.Espresso, CupSize.Small);
Simple Factory β one class, one method, parameter-based. Easier, good enough for most cases. Factory Method β inheritance-based, subclasses override creation. Better when creation logic differs per context.
.NET Real-World Usageβ
IHttpMessageHandlerFactory.CreateHandler()β creates HTTP handlersDbProviderFactory.CreateConnection()β creates DB connections for different providersTaskFactory.StartNew()β creates and schedules tasksActivator.CreateInstance()β runtime type instantiation
When to Useβ
- A class can't anticipate which object it must create
- You want to delegate instantiation to subclasses
- You need to decouple client code from concrete product classes
- You're building a framework where users plug in their own implementations
When NOT to Useβ
- When there's only one product type β a simple constructor is enough
- When the creation logic is trivial β don't add a factory just for
new Foo() - When you need families of related products β use Abstract Factory instead
Key Takeawaysβ
- The Factory Method is about deferring creation to subclasses β the base class doesn't know which concrete product it gets
- The client (base class) works with the abstract product interface β it's decoupled from concrete types
- Open/Closed Principle: add new product types by adding new creator subclasses, without modifying existing code
- A Simple Factory is often good enough β use the GoF pattern when subclass-based flexibility is needed
Interview Questionsβ
Q: What's the difference between Simple Factory and Factory Method? Simple Factory is one class with a switch/if β it's centralized. Factory Method uses inheritance β each subclass overrides the creation method.
Q: How does Factory Method relate to Open/Closed Principle? New product types are added by creating new creator subclasses. Existing code never changes β it only calls the abstract factory method.
Q: When would you use Factory Method over Abstract Factory? Factory Method creates one product type. Abstract Factory creates families of related products. Use Factory Method when you only need one product.
Related Topicsβ
- Abstract Factory β creating families of related products
- SOLID β OCP β Factory Method embodies the Open/Closed Principle
- Dependency Injection β DI containers often act as factories