Skip to main content

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​

ProblemPattern That Solves It
Need exactly one instance of a class (e.g., configuration, logger)Singleton
Want to delegate "which class to instantiate" to subclassesFactory Method
Need to create families of related objects without coupling to concrete typesAbstract Factory
Building a complex object step-by-step with many optional partsBuilder
Want to clone an existing object instead of building from scratchPrototype

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​

PatternIntentWhen to Use
SingletonOne instance, global accessShared state: config, logging, connection pool
Factory MethodDefer instantiation to subclassesA class can't anticipate which object it must create
Abstract FactoryFamilies of related productsUI themes, multi-vendor systems, cross-platform code
BuilderStep-by-step complex constructionObjects with many optional parameters or assembly steps
PrototypeClone existing objectsExpensive creation, or runtime-configured object templates

Common Pitfalls​

  • Over-engineering: Don't wrap every new in 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.