Creational Design Patterns
What Are Creational Patterns?β
Creational patterns abstract the process of object creation. Instead of scattering new calls throughout your codebase, these patterns centralize how objects get built β giving you control over what gets created, when, and how many.
Why They Matterβ
| Problem | Pattern That Solves It |
|---|---|
| Need exactly one instance of a class (e.g., configuration, logger) | Singleton |
| Want to delegate "which class to instantiate" to subclasses | Factory Method |
| Need to create families of related objects without coupling to concrete types | Abstract Factory |
| Building a complex object step-by-step with many optional parts | Builder |
| Want to clone an existing object instead of building from scratch | Prototype |
The Coffee Shop Domainβ
All examples in this section use a Coffee Shop domain. Here's the core model we build on:
// Base product
public abstract class Coffee
{
public string Name { get; init; } = "";
public double Price { get; init; }
public List<string> Ingredients { get; init; } = new();
public CupSize Size { get; init; } = CupSize.Medium;
public override string ToString() =>
$"{Name} ({Size}) β ${Price:F2} [{string.Join(", ", Ingredients)}]";
}
public enum CupSize { Small, Medium, Large }
// Concrete products
public class Espresso : Coffee
{
public Espresso()
{
Name = "Espresso";
Price = 2.50;
Ingredients = new() { "Espresso Shot" };
}
}
public class Latte : Coffee
{
public Latte()
{
Name = "Latte";
Price = 4.00;
Ingredients = new() { "Espresso Shot", "Steamed Milk" };
}
}
public class Cappuccino : Coffee
{
public Cappuccino()
{
Name = "Cappuccino";
Price = 3.75;
Ingredients = new() { "Espresso Shot", "Steamed Milk", "Foam" };
}
}
Pattern Comparisonβ
| Pattern | Intent | When to Use |
|---|---|---|
| Singleton | One instance, global access | Shared state: config, logging, connection pool |
| Factory Method | Defer instantiation to subclasses | A class can't anticipate which object it must create |
| Abstract Factory | Families of related products | UI themes, multi-vendor systems, cross-platform code |
| Builder | Step-by-step complex construction | Objects with many optional parameters or assembly steps |
| Prototype | Clone existing objects | Expensive creation, or runtime-configured object templates |
Common Pitfallsβ
- Over-engineering: Don't wrap every
newin a factory. Use these patterns when the creation logic is complex or needs to vary. - Singleton abuse: Singleton makes testing hard and hides dependencies. Prefer DI-managed singletons in ASP.NET Core.
- Builder for simple objects: If the object has 2-3 required fields and no optional ones, a constructor is enough.
- Prototype and deep copy: Cloning nested objects requires deep copy β shallow copy leads to shared mutable state bugs.
Related Topicsβ
- SOLID Principles β creational patterns heavily rely on SRP and DIP
- Dependency Injection β the DI container often replaces hand-written factories and singletons
- Structural Patterns β how to compose objects after creation
- Behavioral Patterns β how created objects communicate