Fundamentals 32 min read

Master Creational Design Patterns: Singleton, Prototype, Factory, Abstract Factory & Builder Explained

This comprehensive guide explains creational design patterns—including Singleton, Prototype, Factory Method, Abstract Factory, and Builder—detailing their definitions, characteristics, structures, Java implementations, code examples, and typical application scenarios for reducing coupling and improving flexibility in software development.

Intelligent Backend & Architecture
Intelligent Backend & Architecture
Intelligent Backend & Architecture
Master Creational Design Patterns: Singleton, Prototype, Factory, Abstract Factory & Builder Explained

Creational Design Patterns

The main focus of creational design patterns is “how to create objects,” separating object creation from usage to reduce system coupling; factories handle creation so users need not know the details, similar to buying products without knowing how they are manufactured.

1. Singleton Pattern

Ensures a class has only one instance and provides a global access point. It is used in operating‑system components, thread pools, configuration objects, caches, etc.

Characteristics

Only one object exists.

The instance is created by the class itself.

The class provides a global access method.

Implementation

Two forms are common:

Lazy (lazy‑initialization) Singleton – the instance is created when first requested.

Eager (hungry) Singleton – the instance is created at class loading.

public class LazySingleton {
    private static volatile LazySingleton instance = null;
    private LazySingleton() {}
    public static synchronized LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}
public class HungrySingleton {
    private static final HungrySingleton instance = new HungrySingleton();
    private HungrySingleton() {}
    public static HungrySingleton getInstance() {
        return instance;
    }
}

Typical Use Cases

When only one object is required (e.g., system‑wide configuration, logger).

Shared resources such as caches, connection pools, or counters.

2. Prototype Pattern

Creates new objects by copying an existing prototype, which is useful when object creation is costly or complex. The pattern supports shallow and deep cloning.

Structure

AbstractPrototype – declares the clone() method.

ConcretePrototype – implements Cloneable and defines cloning behavior.

public class Realizetype implements Cloneable {
    public Realizetype() { System.out.println("Prototype created!"); }
    @Override
    public Object clone() throws CloneNotSupportedException {
        System.out.println("Prototype cloned!");
        return super.clone();
    }
}

Example: cloning a citation object and then modifying a field.

class Citation implements Cloneable {
    String name, info, college;
    public Citation(String n, String i, String c) {
        this.name = n; this.info = i; this.college = c;
        System.out.println("Citation created!");
    }
    public void setName(String n) { this.name = n; }
    @Override
    public Object clone() throws CloneNotSupportedException {
        System.out.println("Citation cloned!");
        return super.clone();
    }
    public void display() {
        System.out.println(name + info + college);
    }
}

3. Factory Method Pattern

Defines an interface for creating a product, letting subclasses decide which concrete class to instantiate. This promotes the Open/Closed principle because new product types can be added without modifying existing factory code.

Structure

Product – the product interface.

ConcreteProduct – implements the product interface.

Factory (Creator) – declares the factory method newProduct().

ConcreteFactory – overrides the factory method to return a concrete product.

interface Product { void show(); }

class ConcreteProduct1 implements Product {
    public void show() { System.out.println("Concrete product 1 display..."); }
}

class ConcreteProduct2 implements Product {
    public void show() { System.out.println("Concrete product 2 display..."); }
}

interface AbstractFactory { Product newProduct(); }

class ConcreteFactory1 implements AbstractFactory {
    public Product newProduct() {
        System.out.println("Factory 1 creates ConcreteProduct1");
        return new ConcreteProduct1();
    }
}

class ConcreteFactory2 implements AbstractFactory {
    public Product newProduct() {
        System.out.println("Factory 2 creates ConcreteProduct2");
        return new ConcreteProduct2();
    }
}

4. Abstract Factory Pattern

Provides an interface for creating families of related or dependent objects without specifying their concrete classes. It is useful when a system must work with multiple product families (e.g., different brands of TVs and air‑conditioners).

Structure

AbstractFactory – declares creation methods for each product type.

ConcreteFactory – implements the creation methods to produce a specific family of products.

AbstractProductA / AbstractProductB – product interfaces for each product tier.

ConcreteProductA1, ConcreteProductB1, … – concrete implementations belonging to the same family.

interface AbstractFactory {
    Product1 newProduct1();
    Product2 newProduct2();
}

class ConcreteFactory1 implements AbstractFactory {
    public Product1 newProduct1() { return new ConcreteProduct11(); }
    public Product2 newProduct2() { return new ConcreteProduct21(); }
}

class ConcreteFactory2 implements AbstractFactory {
    public Product1 newProduct1() { return new ConcreteProduct12(); }
    public Product2 newProduct2() { return new ConcreteProduct22(); }
}

5. Builder Pattern

Separates the construction of a complex object from its representation, allowing the same construction process to create different representations. It is ideal for objects composed of many parts that can be assembled in a fixed order while the parts themselves may vary.

Structure

Product – the complex object with multiple parts.

Builder (abstract) – declares methods to build each part and a getResult() method.

ConcreteBuilder – implements the steps to create specific parts.

Director – orchestrates the building sequence using a Builder.

class Product {
    private String partA, partB, partC;
    public void setPartA(String a){ this.partA = a; }
    public void setPartB(String b){ this.partB = b; }
    public void setPartC(String c){ this.partC = c; }
    public void show(){ System.out.println("Product built with parts: " + partA + ", " + partB + ", " + partC); }
}

abstract class Builder {
    protected Product product = new Product();
    public abstract void buildPartA();
    public abstract void buildPartB();
    public abstract void buildPartC();
    public Product getResult(){ return product; }
}

class ConcreteBuilder extends Builder {
    public void buildPartA(){ product.setPartA("Part A"); }
    public void buildPartB(){ product.setPartB("Part B"); }
    public void buildPartC(){ product.setPartC("Part C"); }
}

class Director {
    private Builder builder;
    public Director(Builder b){ this.builder = b; }
    public Product construct(){
        builder.buildPartA();
        builder.buildPartB();
        builder.buildPartC();
        return builder.getResult();
    }
}

Example: building a living‑room object (walls, TV, sofa) with different concrete decorators.

class Parlour {
    private String wall, TV, sofa;
    public void setWall(String w){ this.wall = w; }
    public void setTV(String t){ this.TV = t; }
    public void setSofa(String s){ this.sofa = s; }
    public void show(){ System.out.println("Living room built: " + wall + ", " + TV + ", " + sofa); }
}

abstract class Decorator {
    protected Parlour product = new Parlour();
    public abstract void buildWall();
    public abstract void buildTV();
    public abstract void buildSofa();
    public Parlour getResult(){ return product; }
}

class ConcreteDecorator1 extends Decorator {
    public void buildWall(){ product.setWall("Wall type 1"); }
    public void buildTV(){ product.setTV("TV model A"); }
    public void buildSofa(){ product.setSofa("Sofa style X"); }
}

class ConcreteDecorator2 extends Decorator {
    public void buildWall(){ product.setWall("Wall type 2"); }
    public void buildTV(){ product.setTV("TV model B"); }
    public void buildSofa(){ product.setSofa("Sofa style Y"); }
}

class ProjectManager {
    private Decorator builder;
    public ProjectManager(Decorator b){ this.builder = b; }
    public Parlour decorate(){
        builder.buildWall();
        builder.buildTV();
        builder.buildSofa();
        return builder.getResult();
    }
}

These creational patterns help developers manage object creation, improve code reuse, and adhere to solid design principles.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

SingletonprototypeAbstract FactoryFactory MethodBuilder
Intelligent Backend & Architecture
Written by

Intelligent Backend & Architecture

We share personal insights on intelligent, automated backend technologies, along with practical AI knowledge, algorithms, and architecture design, grounded in real business scenarios.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.