Creational Design Patterns

Author: Htunn Thu Thu

Date: January 4, 2026

Tags: #SoftwareDesign #TypeScript #DesignPatterns #Creational

Introduction

Creational patterns solve the problem of creating objects in a flexible and reusable way. When I built my Agentic LLM Search project, I needed to instantiate different LLM providers (Azure OpenAI, local TinyLlama) without hardcoding dependencies. Creational patterns made this possible.

This guide covers four essential creational patterns I use regularly in my TypeScript projects:

  • Factory Pattern - Creating objects without specifying exact classes

  • Singleton Pattern - Ensuring only one instance exists

  • Builder Pattern - Constructing complex objects step by step

  • Prototype Pattern - Cloning objects efficiently


Factory Pattern

Provides an interface for creating objects without specifying their exact class.

The Problem I Had

In my Agentic LLM project, I needed to create different LLM providers based on configuration:

My Solution: Factory Pattern

I created a factory to encapsulate provider creation:

Benefits I Gained

  • Decoupling: AgentService doesn't know about concrete provider classes

  • Easy extension: Adding new providers doesn't change client code

  • Centralized creation: All provider logic in one place

  • Testability: Easy to inject mock providers


Singleton Pattern

Ensures a class has only one instance and provides global access to it.

The Problem I Had

In my IoT monitoring platform, I had multiple components trying to create database connections:

My Solution: Singleton Pattern

I ensured only one database connection exists:

Thread-Safe Singleton (Bonus)

For environments with concurrent access, here's a thread-safe version:

When to Avoid Singletons

Singletons can make testing harder. Here's my approach:


Builder Pattern

Constructs complex objects step by step.

The Problem I Had

In my MCP server project, I needed to build complex HTTP requests with many optional parameters:

My Solution: Builder Pattern

I created a fluent builder interface:

Real-World Example: Query Builder

Here's how I use the builder pattern for database queries in my IoT platform:


Prototype Pattern

Creates new objects by cloning existing ones.

The Problem I Had

In my IoT platform, I needed to create sensor configurations that were mostly similar but with slight variations:

My Solution: Prototype Pattern

I implemented cloneable configurations:

Advanced: Prototype Registry

For my MCP server, I created a registry of configuration prototypes:


Combining Patterns: Real Example

Here's how I combined multiple creational patterns in my Agentic LLM project:


When to Use Each Pattern

Factory Pattern

βœ… Use when:

  • You need to create different types of objects based on input

  • Object creation logic is complex

  • You want to decouple client code from concrete classes

❌ Avoid when:

  • You only have one type of object

  • Creation logic is trivial (just use new)

Singleton Pattern

βœ… Use when:

  • You genuinely need exactly one instance (database connection, config)

  • The instance needs global access

  • Instance creation is expensive

❌ Avoid when:

  • Testing is important (singletons make testing harder)

  • You might need multiple instances later

  • Can use dependency injection instead

Builder Pattern

βœ… Use when:

  • Objects have many optional parameters

  • Construction requires multiple steps

  • You want readable, fluent APIs

❌ Avoid when:

  • Objects are simple with few parameters

  • Construction is straightforward

Prototype Pattern

βœ… Use when:

  • Creating new objects is expensive

  • You need variations of similar objects

  • Object initialization is complex

❌ Avoid when:

  • Objects are simple to create from scratch

  • Deep cloning adds unnecessary complexity


Conclusion

Creational patterns give you flexible ways to create objects:

  • Factory: Abstracts object creation

  • Singleton: Ensures single instance

  • Builder: Constructs complex objects clearly

  • Prototype: Clones objects efficiently

I use these patterns daily in my TypeScript projects. The key is applying them where they add value, not using them everywhere just because they exist.

What's Next?

References


Previous: ← Design Principles | Next: Structural Patterns β†’

Last updated