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.
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.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
