Metadata Card
- Prerequisites: Chapter 7 (SOLID Principles)
- Estimated Time: 50 minutes
- Core Difficulty: Intermediate
- Completion Milestone: Be able to identify and apply 5 creational patterns in your project
Your Progress
Your machine needs to produce various parts: gears, springs, levers, bearings — each with ever-growing specifications, longer construction parameters, and more complex configuration per order.
You notice a pattern: you're always using the same forge with different recipes. The old City of Artisans workshop manual says: "Encapsulate the process of creation. Don't make every worker build their own furnace." Your Task
new is the most direct way to create objects — but it's often not good enough. Sometimes you need a single global instance (Singleton), sometimes you want subclasses to decide which object to create (Factory Method), sometimes you need to build a complex object with many optional parameters (Builder), sometimes you want to copy an object without new (Prototype). Creational patterns solve the core problem: separating the act of creating objects from the act of using them.
Chapter tiers
- Required reading: Singleton, Factory Method, Builder
- Selective: Abstract Factory
- Advanced: Prototype
This chapter won't require you to master
- Object Pool pattern
- Dependency injection container internals
Breaking Ground · Tracing the Source
You wrote a logging service — one instance for the entire system. But other developers called new Logger() in their own modules, each with a different instance. Your log level was configured three times — DEUBG, info, Info. Logs scattered everywhere.
Your reaction: "They shouldn't create their own Logger — they should use the same instance I prepared." Your intuition is right: you need a Singleton.
First Layer: Singleton — Globally Unique Instance
Ensures a class has only one runtime instance. Useful for logging, database connection pooling, and configuration managers.
public class LoggerService {
private static final LoggerService INSTANCE = new LoggerService();
private LogLevel level = LogLevel.INFO;
private LoggerService() {}
public static LoggerService getInstance() { return INSTANCE; }
public void log(String message, LogLevel level) {
if (level.ordinal() >= this.level.ordinal()) {
System.out.println("[" + level + "] " + message);
}
}
public void setLevel(LogLevel level) { this.level = level; }
}Second Layer: Factory Method
Define an interface for creating an object, but let subclasses decide which class to instantiate.
public abstract class RewardFactory {
public abstract Reward createReward();
}
public class CoinRewardFactory extends RewardFactory {
public Reward createReward() { return new CoinReward(100); }
}
public class ExperienceRewardFactory extends RewardFactory {
public Reward createReward() { return new ExperienceReward(500); }
}Third Layer: Builder
Separate the construction of a complex object from its representation.
public class TournamentConfig {
private final String name;
private final int maxPlayers;
private final int minLevel;
private final boolean allowTeams;
private final String prizeType;
public static class Builder {
private String name = "Default Tournament";
private int maxPlayers = 8;
private int minLevel = 1;
private boolean allowTeams = false;
private String prizeType = "coins";
public Builder name(String val) { this.name = val; return this; }
public Builder maxPlayers(int val) { this.maxPlayers = val; return this; }
public TournamentConfig build() { return new TournamentConfig(this); }
}
private TournamentConfig(Builder b) { /* assign fields */ }
}
// Usage
TournamentConfig config = new TournamentConfig.Builder()
.name("Spring Championship")
.maxPlayers(64)
.build();Fourth Layer: Prototype
Create new objects by copying an existing object (clone), avoiding costly creation.
public abstract class GameCharacter implements Cloneable {
public GameCharacter clone() { return (GameCharacter) super.clone(); }
}Fifth Layer: Abstract Factory
Provide an interface for creating families of related or dependent objects without specifying their concrete classes.
Common Pitfalls
Pitfall 1: Singleton in a distributed system. A singleton is only single within a JVM process. Multiple instances in a cluster are not singletons. Use distributed configuration for shared state.
Pitfall 2: Using Factory Method when a simple constructor suffices. Don't create a factory hierarchy for every single class.
Pitfall 3: Builder with too many optional fields. If almost every field is optional, the object might be poorly designed.
Passing Challenges
- Warm up: Identify a Singleton in your project. Is the global state justified?
- Challenge: Refactor a complex constructor (5+ parameters) to use Builder.
- Observe: Look at how Java's
StringBuilderorStream.Builderimplements the Builder pattern.
Traveler's Notes
Creational patterns separate the "how" of object creation from the "what" of object usage. Singleton controls uniqueness, Factory delegates creation to subclasses, Builder handles complex construction, Prototype clones instead of constructs, and Abstract Factory coordinates families of related objects.
Next: Structural Patterns (Chapter 9).