Knowledge Guide
HomeOO & Low-Level Design

Creational

Step 5 in the OO & Low-Level Design path · 5 concepts · 0 problems

0 / 5 complete

📘 Learn Creational from zero

Start from the problem. Normal object creation is new Car(). That looks harmless, but the keyword new hardwires the exact concrete class into the code that uses it. Creational patterns answer one question: how do we create objects without our code being rigidly glued to specific concrete classes — and without making construction itself a mess?

Analogy: a restaurant kitchen. A customer does not assemble their own burger. They give an order to a kitchen and receive a finished dish — they never touch the raw ingredients or know the recipe. If the chef swaps beef for a plant patty, the customer's experience is unchanged. The customer is decoupled from how the food is built. That separation between "what I want" and "how it is built" is the whole family of creational patterns.

Worked example. Suppose a game spawns enemies:

Now imagine an Orc must always come with an Orc-themed weapon and shield, never a Troll's. Bundling those related products is Abstract Factory. If Orc construction took 50 mostly-optional fields, you would Builder it. If a fully configured exemplar already exists, you Prototype (clone) it. If only one global spawner may exist, that spawner is a Singleton.

Key insight: every creational pattern is one tactic for the same GoF goal — program to an interface, not an implementation, by centralizing and abstracting the new.

✨ Added by the guide to build intuition — not from the source course.

🎯 Guided practice

  1. Easy — Make a Logger a Singleton. Requirement: every part of an app must write to the same log buffer; two loggers would split the logs.

    Step 1 — Spot the trigger: "exactly one, shared access" then Singleton.

    Step 2 — Block other instantiation: make the constructor private so no caller can run new Logger().

    Step 3 — Provide the single access point: a static getInstance() returning the one stored instance — created on first call (lazy) or eagerly as a static final field.

    Step 4 — Handle concurrency: if two threads call lazy getInstance() at once, you can create two objects. Fix with eager init, the initialization-on-demand holder idiom (class-loading guarantees one), or double-checked locking on a volatile field. Say this out loud — interviewers reliably probe thread safety, and "DCL without volatile" is a classic trap.

    Takeaway: Singleton = private constructor + static accessor + a safely-published single instance.

  2. Medium — Build a cross-platform UI toolkit. Requirement: render a Button and a Checkbox that match the OS — all macOS, or all Windows, never mixed.

    Step 1 — Recognize the family: two related products (Button, Checkbox) that must vary together by one theme then this is Abstract Factory, not a lone Factory Method.

    Step 2 — Define abstract products: interfaces Button and Checkbox, with concretes MacButton/WinButton and MacCheckbox/WinCheckbox.

    Step 3 — Define the abstract factory: interface GUIFactory with createButton() and createCheckbox(). Two implementations: MacFactory returns Mac products; WinFactory returns Win products. Since each factory only ever returns one family, mixing is impossible by construction.

    Step 4 — Wire it once: at startup pick GUIFactory f = onMac ? new MacFactory() : new WinFactory();. The rest of the app calls f.createButton() / f.createCheckbox() and never references a concrete class.

    Step 5 — Verify the win: adding a Linux theme = one new factory plus its products, with zero changes to app code (Open/Closed Principle).

    Takeaway: Abstract Factory groups several creation methods (each often a Factory Method) so whole families of products stay mutually consistent.

✨ Added by the guide — work these before the full problem set.

Lessons in this topic