1. The Hook (The "Byte-Sized" Intro)
- In a Nutshell: Creational patterns control object creation. Singleton = only one instance (database connection), Factory Method = subclass decides which class to instantiate, Abstract Factory = family of related objects, Builder = step-by-step construction (fluent API), Prototype = clone objects.
- Benefits: Flexibility, decoupling, control.
- Use: Singleton for shared resources, Factory for families of objects, Builder for complex objects, Prototype for expensive initialization!
Think of manufacturing. Singleton = one CEO (only one instance). Factory = car factory (choose sedan vs SUV). Abstract Factory = furniture set (modern vs Victorian, all match). Builder = custom PC (choose CPU, RAM, GPU step-by-step). Prototype = photocopier (clone documents)!
2. Conceptual Clarity (The "Simple" Tier)
💡 The Analogy
- Singleton: Government president (one at a time)
- Factory: Restaurant kitchen (orders → dishes)
- Builder: LEGO instructions (step-by-step assembly)
- Prototype: Copy machine (duplicate originals)
3. Technical Mastery (The "Deep Dive")
Creational Patterns Overview
| Pattern | Purpose | Use When |
|---|---|---|
| Singleton | One instance globally | Shared resource (DB, logger) |
| Factory Method | Defer instantiation to subclasses | Product type varies |
| Abstract Factory | Family of related objects | Cross-platform UI |
| Builder | Complex object construction | Many optional parameters |
| Prototype | Clone objects | Expensive initialization |
4. Interactive & Applied Code
java
// ===========================================
// 1. SINGLETON PATTERN
// ===========================================
// ❌ BAD: Not singleton
class Database {
Database() {
// Expensive connection
}
}
// Multiple instances = resource waste!
// ✅ GOOD: Thread-safe singleton (Bill Pugh)
class Database {
private Database() {}
private static class Holder {
static final Database INSTANCE = new Database();
}
public static Database getInstance() {
return Holder.INSTANCE; // Lazy, thread-safe!
}
}
// Usage:
Database db1 = Database.getInstance();
Database db2 = Database.getInstance();
// db1 == db2 (same instance!)
// ✅ BEST: Enum singleton
enum DatabaseConnection {
INSTANCE;
public void connect() {
System.out.println("Connected");
}
}
// Usage: DatabaseConnection.INSTANCE.connect();
// ===========================================
// 2. FACTORY METHOD PATTERN
// ===========================================
// Product interface
interface Vehicle {
void drive();
}
class Car implements Vehicle {
public void drive() {
System.out.println("Driving car");
}
}
class Truck implements Vehicle {
public void drive() {
System.out.println("Driving truck");
}
}
// Factory
abstract class VehicleFactory {
abstract Vehicle createVehicle();
void deliverVehicle() {
Vehicle v = createVehicle();
v.drive();
}
}
class CarFactory extends VehicleFactory {
Vehicle createVehicle() {
return new Car();
}
}
class TruckFactory extends VehicleFactory {
Vehicle createVehicle() {
return new Truck();
}
}
// Usage:
VehicleFactory factory = new CarFactory();
factory.deliverVehicle(); // Driving car
// ===========================================
// 3. ABSTRACT FACTORY PATTERN
// ===========================================
// Abstract products
interface Button {
void render();
}
interface Checkbox {
void render();
}
// Concrete products (Windows)
class WindowsButton implements Button {
public void render() {
System.out.println("Windows button");
}
}
class WindowsCheckbox implements Checkbox {
public void render() {
System.out.println("Windows checkbox");
}
}
// Concrete products (Mac)
class MacButton implements Button {
public void render() {
System.out.println("Mac button");
}
}
class MacCheckbox implements Checkbox {
public void render() {
System.out.println("Mac checkbox");
}
}
// Abstract factory
interface GUIFactory {
Button createButton();
Checkbox createCheckbox();
}
// Concrete factories
class WindowsFactory implements GUIFactory {
public Button createButton() {
return new WindowsButton();
}
public Checkbox createCheckbox() {
return new WindowsCheckbox();
}
}
class MacFactory implements GUIFactory {
public Button createButton() {
return new MacButton();
}
public Checkbox createCheckbox() {
return new MacCheckbox();
}
}
// Usage:
GUIFactory factory = new WindowsFactory(); // Or MacFactory
Button btn = factory.createButton();
Checkbox chk = factory.createCheckbox();
// All components match the same family!
// ===========================================
// 4. BUILDER PATTERN
// ===========================================
// ❌ BAD: Telescoping constructor
class User {
String name;
int age;
String email;
String phone;
String address;
User(String name) { this.name = name; }
User(String name, int age) { this.name = name; this.age = age; }
User(String name, int age, String email) { /* ... */ }
// Too many constructors!
}
// ✅ GOOD: Builder pattern
class User {
private final String name; // Required
private final int age; // Optional
private final String email; // Optional
private final String phone; // Optional
private User(Builder builder) {
this.name = builder.name;
this.age = builder.age;
this.email = builder.email;
this.phone = builder.phone;
}
static class Builder {
private final String name; // Required
private int age;
private String email;
private String phone;
Builder(String name) {
this.name = name;
}
Builder age(int age) {
this.age = age;
return this;
}
Builder email(String email) {
this.email = email;
return this;
}
Builder phone(String phone) {
this.phone = phone;
return this;
}
User build() {
return new User(this);
}
}
}
// Usage (fluent API):
User user = new User.Builder("Alice")
.age(30)
.email("alice@example.com")
.build();
// ===========================================
// 5. PROTOTYPE PATTERN
// ===========================================
class Document implements Cloneable {
String title;
List<String> pages;
Document(String title) {
this.title = title;
this.pages = new ArrayList<>();
// Expensive initialization
loadTemplate();
}
void loadTemplate() {
// Expensive operation
pages.add("Page 1");
pages.add("Page 2");
}
@Override
public Document clone() {
try {
Document cloned = (Document) super.clone();
cloned.pages = new ArrayList<>(this.pages); // Deep copy
return cloned;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}
// Usage:
Document original = new Document("Template"); // Expensive
Document copy1 = original.clone(); // ✅ Fast!
Document copy2 = original.clone(); // ✅ Fast!
copy1.title = "Copy 1";5. The Comparison & Decision Layer
| Pattern | Use When | Example |
|---|---|---|
| Singleton | Need exactly one instance | Logger, Config |
| Factory | Product type varies | Document (PDF, Word) |
| Abstract Factory | Family of products | GUI (Windows, Mac) |
| Builder | Complex object, many params | HTTP Request, SQL Query |
| Prototype | Expensive initialization | Game objects, Templates |
6. The "Interview Corner" (The Edge)
The "Killer" Interview Question: "How to make Singleton thread-safe?" Answer: Multiple approaches!
java
// ❌ NOT thread-safe
class Singleton {
private static Singleton instance;
static Singleton getInstance() {
if (instance == null) {
instance = new Singleton(); // Race condition!
}
return instance;
}
}
// ✅ Bill Pugh (best)
class Singleton {
private static class Holder {
static final Singleton INSTANCE = new Singleton();
}
static Singleton getInstance() {
return Holder.INSTANCE; // Lazy + thread-safe!
}
}
// ✅ Enum (simplest, best)
enum Singleton {
INSTANCE;
}Pro-Tip: Builder for immutability:
java
// Immutable User with Builder
class User {
private final String name; // final = immutable
private final int age;
private User(Builder b) {
this.name = b.name;
this.age = b.age;
}
static class Builder {
private String name;
private int age;
Builder name(String name) {
this.name = name;
return this;
}
User build() {
return new User(this);
}
}
}
// Combines Builder pattern + immutability!