Design Patterns: Creational Patterns - Singleton, Factory, Builder, Prototype & Abstract Factory
This article is a comprehensive guide to Creational Design Patterns – including Singleton, Factory, Builder, Prototype and Abstract Factory with practical examples.
In a Nutshell
Creational Patterns abstract object creation. Singleton ensures a single instance, Factory encapsulates creation logic, Builder enables step-by-step construction, Prototype clones objects and Abstract Factory creates families of related objects.
Compact Technical Description
Creational Design Patterns are instantiation patterns that control and make the process of object instantiation more flexible.
Important Creational Patterns:
Singleton Pattern
- Purpose: Ensuring a single instance
- Application: Logger, configuration, thread pools
- Implementation: Private constructor, static instance
- Thread-Safety: Synchronized or eager initialization
Factory Method Pattern
- Purpose: Delegating object creation to subclasses
- Application: Frameworks, plugin systems
- Implementation: Abstract factory method
- Advantage: Loose coupling, extensibility
Abstract Factory Pattern
- Purpose: Creating families of related objects
- Application: UI toolkits, database drivers
- Implementation: Factory interface with concrete factories
- Advantage: Consistent object families
Builder Pattern
- Purpose: Step-by-step construction of complex objects
- Application: Configuration objects, DSLs
- Implementation: Fluent interface, separate builder class
- Advantage: Readability, flexibility
Prototype Pattern
- Purpose: Creating objects by cloning
- Application: Performance-optimized creation
- Implementation: Cloneable interface, clone() method
- Advantage: Cost savings with expensive creation
Exam-Relevant Key Points
- Creational Patterns: Instantiation patterns for flexible object creation
- Singleton: Only one instance, global access points
- Factory Method: Object creation through subclasses
- Abstract Factory: Creating families of objects
- Builder: Step-by-step construction of complex objects
- Prototype: Creating objects by cloning
- IHK-relevant: Important for flexible software architecture
Core Components
- Singleton: Global instance with controlled access
- Factory Method: Abstracted object creation
- Abstract Factory: Interface for object families
- Builder: Fluent interface for complex construction
- Prototype: Clone-based object creation
- Dependency Injection: Inversion of control
- Factory Configuration: Configuration-based creation
- Object Pool: Object reuse
Practical Examples
1. Singleton Pattern
// Eager Initialization (Thread-Safe)
public class EagerSingleton {
private static final EagerSingleton INSTANCE = new EagerSingleton();
private EagerSingleton() {
// Private Konstruktor verhindert Instanziierung
}
public static EagerSingleton getInstance() {
return INSTANCE;
}
public void doSomething() {
System.out.println("Eager Singleton arbeitet");
}
}
// Lazy Initialization mit Double-Checked Locking
public class LazySingleton {
private static volatile LazySingleton instance;
private LazySingleton() {
// Private Konstruktor
}
public static LazySingleton getInstance() {
if (instance == null) {
synchronized (LazySingleton.class) {
if (instance == null) {
instance = new LazySingleton();
}
}
}
return instance;
}
public void performAction() {
System.out.println("Lazy Singleton in Aktion");
}
}
// Singleton mit Enum (Thread-Safe, Serialization-Safe)
public enum EnumSingleton {
INSTANCE;
public void doWork() {
System.out.println("Enum Singleton arbeitet");
}
}
// Logger als Singleton
public class Logger {
private static volatile Logger instance;
private final List<String> logs = new ArrayList<>();
private Logger() {}
public static Logger getInstance() {
if (instance == null) {
synchronized (Logger.class) {
if (instance == null) {
instance = new Logger();
}
}
}
return instance;
}
public void log(String message) {
String timestamp = new Date().toString();
String logEntry = "[" + timestamp + "] " + message;
logs.add(logEntry);
System.out.println(logEntry);
}
public List<String> getLogs() {
return new ArrayList<>(logs);
}
public void clearLogs() {
logs.clear();
}
}
// Singleton Demo
public class SingletonDemo {
public static void main(String[] args) {
System.out.println("=== Singleton Pattern Demo ===");
// Eager Singleton
EagerSingleton eager1 = EagerSingleton.getInstance();
EagerSingleton eager2 = EagerSingleton.getInstance();
System.out.println("Eager Singleton - Same Instance: " + (eager1 == eager2));
eager1.doSomething();
// Lazy Singleton
LazySingleton lazy1 = LazySingleton.getInstance();
LazySingleton lazy2 = LazySingleton.getInstance();
System.out.println("Lazy Singleton - Same Instance: " + (lazy1 == lazy2));
lazy2.performAction();
// Enum Singleton
EnumSingleton enum1 = EnumSingleton.INSTANCE;
EnumSingleton enum2 = EnumSingleton.INSTANCE;
System.out.println("Enum Singleton - Same Instance: " + (enum1 == enum2));
enum1.doWork();
// Logger Singleton
Logger logger1 = Logger.getInstance();
Logger logger2 = Logger.getInstance();
System.out.println("Logger Singleton - Same Instance: " + (logger1 == logger2));
logger1.log("Application started");
logger2.log("User logged in");
System.out.println("Logs: " + logger1.getLogs());
}
}
2. Factory Method Pattern
// Abstract product class
abstract class Fahrzeug {
protected String marke;
protected String modell;
public Fahrzeug(String marke, String modell) {
this.marke = marke;
this.modell = modell;
}
public abstract void starten();
public abstract void bremsen();
@Override
public String toString() {
return marke + " " + modell;
}
}
// Concrete products
class Auto extends Fahrzeug {
public Auto(String marke, String modell) {
super(marke, modell);
}
@Override
public void starten() {
System.out.println("Auto " + this + " gestartet");
}
@Override
public void bremsen() {
System.out.println("Auto " + this + " gebremst");
}
}
class Motorrad extends Fahrzeug {
public Motorrad(String marke, String modell) {
super(marke, modell);
}
@Override
public void starten() {
System.out.println("Motorrad " + this + " gestartet");
}
@Override
public void bremsen() {
System.out.println("Motorrad " + this + " gebremst");
}
}
// Abstract factory class
abstract class FahrzeugFabrik {
// Factory Method
public abstract Fahrzeug erstelleFahrzeug(String marke, String modell);
// Template Method
public void produziereUndTeste(String marke, String modell) {
Fahrzeug fahrzeug = erstelleFahrzeug(marke, modell);
System.out.println("Produziert: " + fahrzeug);
// Quality test
fahrzeug.starten();
fahrzeug.bremsen();
System.out.println("Test bestanden");
}
}
// Concrete factories
class AutoFabrik extends FahrzeugFabrik {
@Override
public Fahrzeug erstelleFahrzeug(String marke, String modell) {
return new Auto(marke, modell);
}
}
class MotorradFabrik extends FahrzeugFabrik {
@Override
public Fahrzeug erstelleFahrzeug(String marke, String modell) {
return new Motorrad(marke, modell);
}
}
// Factory with parameter
class FahrzeugFactory {
public static Fahrzeug erstelleFahrzeug(String typ, String marke, String modell) {
switch (typ.toLowerCase()) {
case "auto":
return new Auto(marke, modell);
case "motorrad":
return new Motorrad(marke, modell);
default:
throw new IllegalArgumentException("Unbekannter Fahrzeugtyp: " + typ);
}
}
}
// Factory Method Demo
public class FactoryMethodDemo {
public static void main(String[] args) {
System.out.println("=== Factory Method Pattern Demo ===");
// Factory Method Pattern
FahrzeugFabrik autoFabrik = new AutoFabrik();
FahrzeugFabrik motorradFabrik = new MotorradFabrik();
System.out.println("--- Auto Production ---");
autoFabrik.produziereUndTeste("VW", "Golf");
System.out.println("\n--- Motorcycle Production ---");
motorradFabrik.produziereUndTeste("BMW", "R1200");
// Static Factory
System.out.println("\n--- Static Factory ---");
Fahrzeug vwGolf = FahrzeugFactory.erstelleFahrzeug("auto", "VW", "Golf");
Fahrzeug bmwR1200 = FahrzeugFactory.erstelleFahrzeug("motorrad", "BMW", "R1200");
vwGolf.starten();
bmwR1200.starten();
// Factory with configuration
System.out.println("\n--- Factory with Configuration ---");
FahrzeugKonfigurator konfigurator = new FahrzeugKonfigurator();
Fahrzeug auto1 = konfigurator.erstelleFahrzeug("auto", "Mercedes", "C-Klasse");
Fahrzeug motorrad1 = konfigurator.erstelleFahrzeug("motorrad", "Harley", "Sportster");
auto1.starten();
motorrad1.starten();
}
}
// Factory with configuration
class FahrzeugKonfigurator {
private Map<String, FahrzeugFabrik> fabriken = new HashMap<>();
public FahrzeugKonfigurator() {
fabriken.put("auto", new AutoFabrik());
fabriken.put("motorrad", new MotorradFabrik());
}
public Fahrzeug erstelleFahrzeug(String typ, String marke, String modell) {
FahrzeugFabrik fabrik = fabriken.get(typ.toLowerCase());
if (fabrik == null) {
throw new IllegalArgumentException("Unbekannter Typ: " + typ);
}
return fabrik.erstelleFahrzeug(marke, modell);
}
public void registriereFabrik(String typ, FahrzeugFabrik fabrik) {
fabriken.put(typ.toLowerCase(), fabrik);
}
}
3. Abstract Factory Pattern
// Abstract products for UI theme
interface Button {
void render();
void onClick(Runnable action);
}
interface TextField {
void render();
void setText(String text);
String getText();
}
interface Checkbox {
void render();
void setChecked(boolean checked);
boolean isChecked();
}
// Concrete products - Windows theme
class WindowsButton implements Button {
@Override
public void render() {
System.out.println("[Windows Button rendered]");
}
@Override
public void onClick(Runnable action) {
System.out.println("Windows Button clicked");
action.run();
}
}
class WindowsTextField implements TextField {
private String text = "";
@Override
public void render() {
System.out.println("[Windows TextField: '" + text + "']");
}
@Override
public void setText(String text) {
this.text = text;
}
@Override
public String getText() {
return text;
}
}
class WindowsCheckbox implements Checkbox {
private boolean checked = false;
@Override
public void render() {
System.out.println("[Windows Checkbox: " + (checked ? "X" : " ") + "]");
}
@Override
public void setChecked(boolean checked) {
this.checked = checked;
}
@Override
public boolean isChecked() {
return checked;
}
}
// Concrete products - macOS theme
class MacButton implements Button {
@Override
public void render() {
System.out.println("[macOS Button rendered]");
}
@Override
public void onClick(Runnable action) {
System.out.println("macOS Button clicked");
action.run();
}
}
class MacTextField implements TextField {
private String text = "";
@Override
public void render() {
System.out.println("[macOS TextField: '" + text + "']");
}
@Override
public void setText(String text) {
this.text = text;
}
@Override
public String getText() {
return text;
}
}
class MacCheckbox implements Checkbox {
private boolean checked = false;
@Override
public void render() {
System.out.println("[macOS Checkbox: " + (checked ? "✓" : " ") + "]");
}
@Override
public void setChecked(boolean checked) {
this.checked = checked;
}
@Override
public boolean isChecked() {
return checked;
}
}
// Abstract factory
interface GUIFactory {
Button createButton();
TextField createTextField();
Checkbox createCheckbox();
}
// Concrete factories
class WindowsFactory implements GUIFactory {
@Override
public Button createButton() {
return new WindowsButton();
}
@Override
public TextField createTextField() {
return new WindowsTextField();
}
@Override
public Checkbox createCheckbox() {
return new WindowsCheckbox();
}
}
class MacFactory implements GUIFactory {
@Override
public Button createButton() {
return new MacButton();
}
@Override
public TextField createTextField() {
return new MacTextField();
}
@Override
public Checkbox createCheckbox() {
return new MacCheckbox();
}
}
// Client code
class Application {
private Button button;
private TextField textField;
private Checkbox checkbox;
public Application(GUIFactory factory) {
button = factory.createButton();
textField = factory.createTextField();
checkbox = factory.createCheckbox();
}
public void createUI() {
System.out.println("=== UI is being created ===");
button.render();
textField.render();
checkbox.render();
// Add functionality
button.onClick(() -> {
String text = textField.getText();
System.out.println("Button clicked with text: " + text);
checkbox.setChecked(!checkbox.isChecked());
checkbox.render();
});
textField.setText("Sample text");
textField.render();
}
}
// Abstract Factory Demo
public class AbstractFactoryDemo {
public static void main(String[] args) {
System.out.println("=== Abstract Factory Pattern Demo ===");
// Windows application
System.out.println("\n--- Windows Application ---");
GUIFactory windowsFactory = new WindowsFactory();
Application windowsApp = new Application(windowsFactory);
windowsApp.createUI();
// macOS application
System.out.println("\n--- macOS Application ---");
GUIFactory macFactory = new MacFactory();
Application macApp = new Application(macFactory);
macApp.createUI();
// Factory based on operating system
System.out.println("\n--- Dynamic Factory ---");
String os = System.getProperty("os.name").toLowerCase();
GUIFactory factory;
if (os.contains("mac")) {
factory = new MacFactory();
} else {
factory = new WindowsFactory();
}
Application dynamicApp = new Application(factory);
dynamicApp.createUI();
}
}
4. Builder Pattern
// Complex product
class Computer {
private final String cpu;
private final String gpu;
private final int ram;
private final int storage;
private final boolean hasWifi;
private final boolean hasBluetooth;
private final String operatingSystem;
// Private constructor
private Computer(Builder builder) {
this.cpu = builder.cpu;
this.gpu = builder.gpu;
this.ram = builder.ram;
this.storage = builder.storage;
this.hasWifi = builder.hasWifi;
this.hasBluetooth = builder.hasBluetooth;
this.operatingSystem = builder.operatingSystem;
}
// Getters
public String getCpu() { return cpu; }
public String getGpu() { return gpu; }
public int getRam() { return ram; }
public int getStorage() { return storage; }
public boolean hasWifi() { return hasWifi; }
public boolean hasBluetooth() { return hasBluetooth; }
public String getOperatingSystem() { return operatingSystem; }
@Override
public String toString() {
return "Computer{" +
"cpu='" + cpu + '\'' +
", gpu='" + gpu + '\'' +
", ram=" + ram + "GB" +
", storage=" + storage + "GB" +
", hasWifi=" + hasWifi +
", hasBluetooth=" + hasBluetooth +
", operatingSystem='" + operatingSystem + '\'' +
'}';
}
// Builder class
public static class Builder {
// Required parameters
private final String cpu;
private final String gpu;
// Optional parameters with default values
private int ram = 8;
private int storage = 256;
private boolean hasWifi = true;
private boolean hasBluetooth = false;
private String operatingSystem = "Windows";
// Constructor for required parameters
public Builder(String cpu, String gpu) {
this.cpu = cpu;
this.gpu = gpu;
}
// Fluent interface for optional parameters
public Builder ram(int ram) {
this.ram = ram;
return this;
}
public Builder storage(int storage) {
this.storage = storage;
return this;
}
public Builder wifi(boolean hasWifi) {
this.hasWifi = hasWifi;
return this;
}
public Builder bluetooth(boolean hasBluetooth) {
this.hasBluetooth = hasBluetooth;
return this;
}
public Builder operatingSystem(String operatingSystem) {
this.operatingSystem = operatingSystem;
return this;
}
// Build method
public Computer build() {
// Validation
if (ram < 4) {
throw new IllegalArgumentException("RAM must be at least 4GB");
}
if (storage < 128) {
throw new IllegalArgumentException("Storage must be at least 128GB");
}
return new Computer(this);
}
}
}
// Builder for configuration objects
class Configuration {
private final Map<String, String> properties;
private final List<String> enabledModules;
private final String databaseConnection;
private final int timeout;
private Configuration(Builder builder) {
this.properties = new HashMap<>(builder.properties);
this.enabledModules = new ArrayList<>(builder.enabledModules);
this.databaseConnection = builder.databaseConnection;
this.timeout = builder.timeout;
}
public static class Builder {
private Map<String, String> properties = new HashMap<>();
private List<String> enabledModules = new ArrayList<>();
private String databaseConnection = "localhost:5432";
private int timeout = 30;
public Builder property(String key, String value) {
properties.put(key, value);
return this;
}
public Builder module(String module) {
enabledModules.add(module);
return this;
}
public Builder databaseConnection(String connection) {
this.databaseConnection = connection;
return this;
}
public Builder timeout(int seconds) {
this.timeout = seconds;
return this;
}
public Configuration build() {
return new Configuration(this);
}
}
// Getters and toString
public Map<String, String> getProperties() { return new HashMap<>(properties); }
public List<String> getEnabledModules() { return new ArrayList<>(enabledModules); }
public String getDatabaseConnection() { return databaseConnection; }
public int getTimeout() { return timeout; }
@Override
public String toString() {
return "Configuration{" +
"properties=" + properties +
", enabledModules=" + enabledModules +
", databaseConnection='" + databaseConnection + '\'' +
", timeout=" + timeout +
'}';
}
}
// Builder Pattern Demo
public class BuilderDemo {
public static void main(String[] args) {
System.out.println("=== Builder Pattern Demo ===");
// Simple computer with builder
Computer gamingPC = new Computer.Builder("Intel i9", "NVIDIA RTX 3080")
.ram(32)
.storage(1000)
.wifi(true)
.bluetooth(true)
.operatingSystem("Windows 11")
.build();
System.out.println("Gaming PC: " + gamingPC);
// Minimal computer
Computer officePC = new Computer.Builder("Intel i5", "Intel HD Graphics")
.build();
System.out.println("Office PC: " + officePC);
// Configuration with builder
Configuration config = new Configuration.Builder()
.property("app.name", "MyApp")
.property("app.version", "1.0.0")
.module("authentication")
.module("logging")
.module("database")
.databaseConnection("prod.db.server.com:5432")
.timeout(60)
.build();
System.out.println("\nConfiguration: " + config);
// Nested builder
System.out.println("\n--- Nested Builder ---");
Computer server = new Computer.Builder("AMD EPYC", "AMD Radeon VII")
.ram(128)
.storage(4000)
.wifi(false)
.operatingSystem("Ubuntu Server")
.build();
System.out.println("Server: " + server);
// Builder with validation
try {
Computer invalidPC = new Computer.Builder("Intel i3", "Intel HD")
.ram(2) // Invalid
.build();
} catch (IllegalArgumentException e) {
System.out.println("Validation error: " + e.getMessage());
}
}
}
5. Prototype Pattern
// Prototype Interface
interface Prototype<T> {
T clone();
}
// Concrete Prototypes
class Dokument implements Prototype<Dokument> {
private String titel;
private String inhalt;
private List<String> tags;
private Date erstellDatum;
public Dokument(String titel, String inhalt) {
this.titel = titel;
this.inhalt = inhalt;
this.tags = new ArrayList<>();
this.erstellDatum = new Date();
}
// Copy Constructor
private Dokument(Dokument original) {
this.titel = original.titel;
this.inhalt = original.inhalt;
this.tags = new ArrayList<>(original.tags);
this.erstellDatum = new Date(original.erstellDatum.getTime());
}
@Override
public Dokument clone() {
return new Dokument(this);
}
// Getter and Setter
public String getTitel() { return titel; }
public void setTitel(String titel) { this.titel = titel; }
public String getInhalt() { return inhalt; }
public void setInhalt(String inhalt) { this.inhalt = inhalt; }
public void addTag(String tag) { tags.add(tag); }
public List<String> getTags() { return new ArrayList<>(tags); }
@Override
public String toString() {
return "Dokument{" +
"titel='" + titel + '\'' +
", inhalt='" + inhalt + '\'' +
", tags=" + tags +
", erstellDatum=" + erstellDatum +
'}';
}
}
// Graphic Object as Prototype
class GrafikObjekt implements Prototype<GrafikObjekt> {
private String typ;
private int x, y;
private int breite, hoehe;
private String farbe;
private List<GrafikObjekt> kinder;
public GrafikObjekt(String typ, int x, int y, int breite, int hoehe, String farbe) {
this.typ = typ;
this.x = x;
this.y = y;
this.breite = breite;
this.hoehe = hoehe;
this.farbe = farbe;
this.kinder = new ArrayList<>();
}
// Deep Clone with Copy Constructor
private GrafikObjekt(GrafikObjekt original) {
this.typ = original.typ;
this.x = original.x;
this.y = original.y;
this.breite = original.breite;
this.hoehe = original.hoehe;
this.farbe = original.farbe;
this.kinder = new ArrayList<>();
// Deep clone for children
for (GrafikObjekt kind : original.kinder) {
this.kinder.add(kind.clone());
}
}
@Override
public GrafikObjekt clone() {
return new GrafikObjekt(this);
}
public void addKind(GrafikObjekt kind) {
kinder.add(kind);
}
public void verschieben(int deltaX, int deltaY) {
this.x += deltaX;
this.y += deltaY;
// Move children as well
for (GrafikObjekt kind : kinder) {
kind.verschieben(deltaX, deltaY);
}
}
@Override
public String toString() {
return "GrafikObjekt{" +
"typ='" + typ + '\'' +
", x=" + x + ", y=" + y +
", groesse=" + breite + "x" + hoehe +
", farbe='" + farbe + '\'' +
", kinder=" + kinder.size() +
'}';
}
}
// Prototype Registry
class PrototypeRegistry {
private Map<String, Prototype<?>> prototypen = new HashMap<>();
public void registrierePrototyp(String key, Prototype<?> prototyp) {
prototypen.put(key, prototyp);
}
@SuppressWarnings("unchecked")
public <T extends Prototype<T>> T klonePrototyp(String key) {
Prototype<?> prototyp = prototypen.get(key);
if (prototyp == null) {
throw new IllegalArgumentException("Prototyp nicht gefunden: " + key);
}
return (T) prototyp.clone();
}
public Collection<String> getVerfuegbarePrototypen() {
return prototypen.keySet();
}
}
// Prototype Manager for Performance Optimization
class PerformancePrototypManager {
private Map<Class<?>, Prototype<?>> cache = new HashMap<>();
@SuppressWarnings("unchecked")
public <T extends Prototype<T>> T getOptimiertesClone(Class<T> klasse, T prototyp) {
if (!cache.containsKey(klasse)) {
cache.put(klasse, prototyp);
}
T cached = (T) cache.get(klasse);
return cached.clone();
}
public void clearCache() {
cache.clear();
}
public int getCacheSize() {
return cache.size();
}
}
// Prototype Pattern Demo
public class PrototypeDemo {
public static void main(String[] args) {
System.out.println("=== Prototype Pattern Demo ===");
// Simple cloning
System.out.println("\n--- Simple Cloning ---");
Dokument original = new Dokument("Bericht", "Dies ist ein Testbericht");
original.addTag("wichtig");
original.addTag("intern");
System.out.println("Original: " + original);
Dokument kopie = original.clone();
kopie.setTitel("Bericht - Kopie");
kopie.addTag("kopie");
System.out.println("Kopie: " + kopie);
System.out.println("Original nach Kopie: " + original);
// Deep Clone with complex objects
System.out.println("\n--- Deep Clone ---");
GrafikObjekt container = new GrafikObjekt("Container", 0, 0, 800, 600, "weiß");
GrafikObjekt button1 = new GrafikObjekt("Button", 10, 10, 100, 30, "blau");
GrafikObjekt button2 = new GrafikObjekt("Button", 120, 10, 100, 30, "grün");
container.addKind(button1);
container.addKind(button2);
System.out.println("Original Container: " + container);
GrafikObjekt geklonteContainer = container.clone();
geklonteContainer.verschieben(50, 50);
System.out.println("Geklonter Container: " + geklonteContainer);
System.out.println("Original nach Verschiebung: " + container);
// Prototype Registry
System.out.println("\n--- Prototype Registry ---");
PrototypeRegistry registry = new PrototypeRegistry();
// Register prototypes
registry.registrierePrototyp("bericht", new Dokument("Standard-Bericht", ""));
registry.registrierePrototyp("button", new GrafikObjekt("Button", 0, 0, 80, 25, "grau"));
// Clone prototypes from registry
Dokument neuerBericht = registry.klonePrototyp("bericht");
neuerBericht.setTitel("Monatsbericht");
neuerBericht.setInhalt("Monatliche Statistiken...");
GrafikObjekt neuerButton = registry.klonePrototyp("button");
neuerButton.verschieben(200, 100);
System.out.println("Neuer Bericht: " + neuerBericht);
System.out.println("Neuer Button: " + neuerButton);
System.out.println("Verfügbare Prototypen: " + registry.getVerfuegbarePrototypen());
// Performance Optimization
System.out.println("\n--- Performance Optimization ---");
PerformancePrototypManager manager = new PerformancePrototypManager();
Dokument template = new Dokument("Template", "Vorlageninhalt");
// Many clones with optimization
long startZeit = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
Dokument schnell = manager.getOptimiertesClone(Dokument.class, template);
schnell.setTitel("Dokument " + i);
}
long endZeit = System.currentTimeMillis();
System.out.println("1000 optimierte Klone: " + (endZeit - startZeit) + "ms");
System.out.println("Cache Größe: " + manager.getCacheSize());
}
}
Creational Patterns Overview
| Pattern | Purpose | When to use | Advantages |
|---|---|---|---|
| Singleton | Ensure one instance | Logger, Configuration | Global access, Memory efficiency |
| Factory Method | Delegate object creation | Frameworks, Plugins | Loose Coupling, Extensibility |
| Abstract Factory | Create object families | UI Toolkits, Database | Consistent objects |
| Builder | Build complex objects step by step | Configuration, DSLs | Readability, Flexibility |
| Prototype | Create objects by cloning | Performance, Templates | Cost efficiency |
Implementation Checklists
Singleton
- Private constructor
- Static instance
- Thread-safety
- Serialization-safety
- Clone protection
Factory Method
- Abstract factory method
- Concrete implementations
- Product hierarchy
- Loose coupling
Abstract Factory
- Factory interface
- Concrete factories
- Product families
- Consistency
Builder
- Fluent interface
- Immutable product
- Validation
- Required/Optional separation
Prototype
- Cloneable interface
- Deep clone
- Prototype registry
- Performance optimization
Advantages and Disadvantages
Advantages of Creational Patterns
- Flexibility: Easy adaptation of object creation
- Reusability: Reusable creation logic
- Encapsulation: Complex logic hidden
- Testability: Easier mocking possibilities
- Maintainability: Centralized creation
Disadvantages
- Complexity: Additional classes and interfaces
- Overhead: More code for simple cases
- Learning curve: Understanding of patterns required
- Over-engineering: Risk with overly complex solutions
Common Exam Questions
-
When do you use Singleton instead of Static Class? Singleton for OO features like inheritance, interfaces, lazy initialization.
-
What is the difference between Factory Method and Abstract Factory? Factory Method creates one product, Abstract Factory creates families of products.
-
Explain the advantage of the Builder Pattern! Step-by-step construction of complex objects with fluent interface and validation.
-
When is Prototype Pattern useful? With expensive object creation or when many similar objects are needed.
Most Important Sources
- https://refactoring.guru/design-patterns/creational-patterns
- https://www.oracle.com/technetwork/java/designpatterns-138485.html
- https://en.wikipedia.org/wiki/Creational_pattern
Recommended Reading: Design Patterns
Design Patterns
Books about design patterns and software design
Design Patterns von Gang of Four
Bei Amazon ansehenAffiliate-Link: Bei einem Kauf erhalten wir möglicherweise eine Provision.
Patterns of Enterprise Application Architecture von Martin Fowler
Bei Amazon ansehenAffiliate-Link: Bei einem Kauf erhalten wir möglicherweise eine Provision.
Refactoring von Martin Fowler
Bei Amazon ansehenAffiliate-Link: Bei einem Kauf erhalten wir möglicherweise eine Provision.

