Skip to content

Creational Patterns#

flowchart LR
  C[Caller]
  F([Factory / Builder / Singleton])
  P[Product]
  C -->|create / get| F --> P

  classDef p fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
  classDef s fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
  classDef r fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
  class C p;
  class F s;
  class P r;

    classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
    classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
    classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
    classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
    classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
    classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
    classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
    classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
    classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
    classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
    class C,F,P service;
Factory Method design pattern UML class diagram
Source: Wikimedia Commons. CC BY-SA / public domain.

Five patterns for hiding how an object gets constructed: Singleton, Factory Method, Abstract Factory, Builder, Prototype.

Singleton#

Single instance, accessed via a static method.

classDiagram
  class Singleton {
    -instance: Singleton
    -Singleton()
    +getInstance() Singleton
    +operation()
  }
  Singleton --> Singleton : returns self
class Logger {
  private static volatile Logger INSTANCE;
  private Logger() {}
  public static Logger getInstance() {
    if (INSTANCE == null) synchronized (Logger.class) {
      if (INSTANCE == null) INSTANCE = new Logger();
    }
    return INSTANCE;
  }
}

Watch: hidden global state, breaks testability. Most languages prefer a single instance passed via DI rather than a true singleton.


Factory Method#

A method on a base class decides which concrete to instantiate.

classDiagram
  class Creator {
    <<abstract>>
    +createProduct() Product
    +operation()
  }
  class ConcreteCreatorA {
    +createProduct() Product
  }
  class ConcreteCreatorB {
    +createProduct() Product
  }
  class Product
  class ConcreteProductA
  class ConcreteProductB
  Creator <|-- ConcreteCreatorA
  Creator <|-- ConcreteCreatorB
  Product <|-- ConcreteProductA
  Product <|-- ConcreteProductB
  ConcreteCreatorA ..> ConcreteProductA
  ConcreteCreatorB ..> ConcreteProductB

Use when the caller shouldn't know which concrete type comes back.


Abstract Factory#

A factory that returns families of related products (e.g. a UI toolkit's Button + Checkbox + Menu).

classDiagram
  class GUIFactory {
    <<interface>>
    +createButton() Button
    +createCheckbox() Checkbox
  }
  class MacFactory
  class WinFactory
  GUIFactory <|-- MacFactory
  GUIFactory <|-- WinFactory
  class Button
  class Checkbox
  class MacButton
  class WinButton
  Button <|-- MacButton
  Button <|-- WinButton

Builder#

Construct a complex object step-by-step. Most useful when an object has many optional parameters.

Pizza p = new Pizza.Builder()
    .size(LARGE)
    .addTopping("cheese")
    .addTopping("olives")
    .crust("thin")
    .build();

Java records / Kotlin data classes / Python kwargs replace some of this, but the fluent-builder is still common.


Prototype#

Clone an existing instance instead of constructing a new one. Useful when construction is expensive.

classDiagram
  class Prototype {
    <<interface>>
    +clone() Prototype
  }
  class Page {
    -title
    -content
    +clone() Page
  }
  Prototype <|.. Page

Choosing among them#

Use Pick
Hide one type's construction Factory Method
Hide a family of types together Abstract Factory
Many optional / required fields Builder
Construction is expensive; you want copies Prototype
You truly need exactly one instance Singleton (sparingly)

Where these show up in this site#

  • Logger framework uses Singleton for the root logger + Factory for appenders.
  • Vending machine / ATM / Hotel management use Builder for complex requests.
  • Chess engine uses Prototype for memento/undo snapshots.

Glossary & fundamentals#

Concepts referenced in this design. Each row links to its canonical page; the tag column shows whether it is a high-level (HLD) or low-level (LLD) concept.

Tag Concept What it is Page
HLD Observability metrics, logs, traces, SLOs observability
LLD Creational patterns Singleton, Factory, Builder, Prototype creational-patterns
LLD Behavioural patterns Strategy, Observer, State, Command, Chain behavioral-patterns
LLD Dependency injection DI / IoC, constructor injection, containers dependency-injection

Quick reference#

Why#

  • Decouple "what to use" from "how to make it".
  • Centralise construction logic so it can be swapped, tested, mocked.

Singleton pitfalls#

  • Acts as global state.
  • Hard to test (must reset between tests).
  • Multi-threaded init needs care (double-checked locking, volatile, or eager init).
  • Frequently better: inject a single instance via the DI container.

Builder vs telescoping constructors#

  • 4 parameters? Reach for Builder.

  • Required vs optional: enforce required in Builder constructor; expose setters for optional.
  • Fluent (return this) reads better.

Modern alternatives#

  • Kotlin: data class + named/default args replaces Builder for many cases.
  • Java records (since 14) cover simple POJOs.
  • Python: keyword arguments + dataclasses replace most of Builder.
  • Go: functional options (WithTimeout(5), WithRetries(3)).

Refs#

  • Design Patterns: Elements of Reusable Object-Oriented Software - Gamma, Helm, Johnson, Vlissides (GoF, 1994).
  • Effective Java (Bloch) - Item 2 (Builder), Item 3 (Singleton).
  • Refactoring.guru patterns gallery.

FAQ#

What are creational design patterns?#

Patterns that abstract the process of creating objects so callers do not depend on concrete classes. They include Singleton, Factory Method, Abstract Factory, Builder, and Prototype.

When should I use Singleton?#

For genuinely one-instance resources like a metrics registry or process-wide cache. Avoid it for service dependencies because Singletons hide coupling and make unit testing harder.

Factory method vs abstract factory?#

Factory method picks one concrete product based on a parameter. Abstract factory creates a family of related products that work together, like a UI toolkit with matching buttons and menus.

When should I prefer Prototype over Builder?#

Prototype clones an existing instance, which is handy when construction is expensive or the source already has the right state. Builder constructs from scratch with full control over each field.

Are creational patterns still relevant in modern code?#

Yes, but often expressed via dependency injection containers and records or data classes. The underlying ideas, hiding construction details and decoupling callers, remain useful.

  • Structural Patterns: structural patterns frequently combine with creational ones at the composition boundary
  • Behavioral Patterns: creational patterns supply objects that behavioral patterns operate on
  • SOLID Principles: DIP and OCP are the primary design forces behind Factory and Abstract Factory

Further reading#

Curated, high-credibility sources for going deeper on this topic.