DEV Community

Cover image for Design patterns, explained: the vocabulary of an object-oriented design interview
Gowtham Potureddi
Gowtham Potureddi

Posted on

Design patterns, explained: the vocabulary of an object-oriented design interview

Design patterns, explained: the vocabulary of an object-oriented design interview

Design patterns are the shared vocabulary of object-oriented design — named solutions to problems that recur so often that giving them names makes a design conversation faster and clearer. In an OOD interview they are rarely a quiz ("list the Gang of Four") and almost always a judgement test: you reach for a pattern to solve a real problem in your design, the interviewer asks why that one, and you defend the choice and its cost. The skill is not reciting twenty-three patterns; it is recognising which small handful actually fit interview problems, applying them where they earn their keep, and — just as important — knowing when not to.

This guide walks the design patterns interview questions that come up for real: the three families patterns fall into, and the six that recur in low-level design rounds — Strategy, Factory, Singleton, Observer, State and Decorator — each with its intent, a short example, and the trade-off the interviewer will probe. The aim is not to memorise definitions but to recognise the shape of a problem and name the pattern that fits it, so that when you put a PricingStrategy interface in a parking-lot design you can say why — and so that when a pattern would only add ceremony, you can say that too.

Title card for an object-oriented design interview guide to design patterns, showing the three pattern families — creational, structural and behavioral — each with its key patterns, and a sketch of a Strategy interface with interchangeable algorithm implementations plugged into a context class, on a dark citrus-and-lavender background.

Why design patterns come up in object-oriented design interviews

Patterns show up two ways: as a direct question ("what design patterns have you used, and when?") and, more often, as the named solution you reach for mid-design. When you decide that pricing should be swappable, you are reaching for Strategy; when a vending machine's behaviour depends on what state it is in, you are reaching for State. The interviewer rewards naming the pattern, justifying it against the requirement, and stating its cost — and penalises the opposite failure, forcing a pattern where a plain method would do.

The interviewer rarely lets a pattern name stand on its own. "You reached for a Singleton for your parking lot. Walk me through what that actually buys you here, what it costs — and then tell me how you'd unit-test a class that depends on it." That question — the trade-off behind the pattern, not its definition — is the one a memorised catalogue can never survive, and the one these questions are really testing.

The rounds on Zynter are modelled on how the loop runs, not scraped from any candidate's recall. What matters for prep is the shape: you name a pattern, and the next sentence asks you to justify it, cost it, or defend it against the simpler alternative you skipped.

What the interviewer is really testing

A design-patterns answer is read on the same four dimensions as any design round. Problem solving — can you match the right pattern to the problem, rather than reaching for the one you know best? Communication — can you state a pattern's intent and trade-off in one plain sentence? Technical execution — when you apply it, does the result actually decouple the code, or just add indirection? Time management — do you use patterns where they pay off, not gold-plate a three-class problem into a pattern parade? Reading this guide teaches the patterns; it does not teach you to defend one while the interviewer offers you a simpler option.

The three families of design patterns

The Gang of Four grouped patterns into three families by the kind of problem they solve. You do not need all twenty-three; you need to know the families and the few that fit interview problems.

Family What it solves Patterns that recur in interviews
Creational How objects get created Singleton, Factory Method, Abstract Factory, Builder
Structural How objects are composed into bigger structures Adapter, Decorator, Facade, Proxy, Composite
Behavioral How objects interact and share responsibility Strategy, Observer, State, Command, Iterator

A diagram of the three design pattern families, showing creational patterns (Singleton, Factory, Builder) grouped around object creation, structural patterns (Adapter, Decorator, Facade, Proxy) grouped around composing objects, and behavioral patterns (Strategy, Observer, State, Command) grouped around how objects interact, each family in its own labelled column.

Strategy — swap an algorithm at runtime

Intent: define a family of interchangeable algorithms behind one interface, so the algorithm can vary without changing the code that uses it. Use it when a behaviour has several variants chosen at runtime — pricing rules, sorting orders, compression schemes. It is the most interview-useful pattern there is, and it is the open/closed and dependency-inversion principles made concrete.

interface PricingStrategy { double price(Ticket t); }
class HourlyPricing  implements PricingStrategy { public double price(Ticket t) { ... } }
class WeekendPricing implements PricingStrategy { public double price(Ticket t) { ... } }

class ParkingLot {
    private PricingStrategy pricing;              // chosen at runtime
    double charge(Ticket t) { return pricing.price(t); }
}
Enter fullscreen mode Exit fullscreen mode

The trade-off to name: Strategy adds a class per algorithm, which is worth it when the variants are real and likely to grow, and over-engineering when there is only ever one.

Factory — centralise object creation

Intent: move the decision of which concrete class to instantiate out of the business logic and into one place. Use it when creation depends on a type or config and you want new ConcreteThing() out of the callers. It keeps the open/closed principle intact: a new type is a new branch in the factory, not scattered new calls across the codebase.

class VehicleFactory {
    static Vehicle create(VehicleType type) {
        return switch (type) {
            case CAR        -> new Car();
            case TRUCK      -> new Truck();
            case MOTORCYCLE -> new Motorcycle();
        };
    }
}
Enter fullscreen mode Exit fullscreen mode

The trade-off: a factory is indirection, justified when construction is non-trivial or varies; for a single, simple constructor it is ceremony.

Singleton — one shared instance (and its cost)

Intent: guarantee a class has exactly one instance with a global access point. Use it when one object genuinely models a single real thing — a single parking lot, one configuration registry. It is the pattern interviewers most want you to be sceptical of, because its costs are real.

class ParkingLot {
    private static final ParkingLot INSTANCE = new ParkingLot();
    private ParkingLot() {}                        // no public constructor
    static ParkingLot getInstance() { return INSTANCE; }
}
Enter fullscreen mode Exit fullscreen mode

The trade-off to volunteer: a Singleton is global mutable state, which makes code hard to test (you cannot swap it for a fake) and hidden coupling (callers depend on it invisibly), and it must be thread-safe. Say you would prefer dependency injection of a single instance over a hard Singleton where testability matters — that scepticism is the senior signal.

Observer — publish and notify

Intent: let one object (the subject) notify a changing set of dependents (observers) when its state changes, without the subject knowing who they are. Use it when several parts of a system must react to an event — a display board updating as parking spots fill, listeners reacting to an order being placed.

interface Observer { void update(Event e); }
class ParkingLot {                                 // the subject
    private List<Observer> observers = new ArrayList<>();
    void subscribe(Observer o) { observers.add(o); }
    void spotFreed() { observers.forEach(o -> o.update(...)); }
}
Enter fullscreen mode Exit fullscreen mode

The trade-off: it decouples publisher from subscribers, at the cost of an indirection that can make the flow harder to follow and, if misused, memory leaks from un-removed observers.

State — behaviour that changes with state

Intent: let an object alter its behaviour when its internal state changes, by delegating to a state object rather than branching on a status flag. Use it when an object is a state machine — a vending machine (idle → money inserted → dispensing), an ATM session, a booking lifecycle.

interface State { void insertCoin(Machine m); void dispense(Machine m); }
class IdleState     implements State { ... }       // each state defines what's legal
class HasMoneyState implements State { ... }
class VendingMachine { private State state; /* delegates to state */ }
Enter fullscreen mode Exit fullscreen mode

The trade-off: State replaces a sprawling if/switch on a status enum with one class per state — cleaner and open/closed when the states and transitions are real, heavier than a flag when there are only two trivial states.

Decorator — layer behaviour without a subclass explosion

Intent: attach responsibilities to an object dynamically by wrapping it in objects that share its interface. Use it when you would otherwise need a subclass for every combination of features — a coffee with milk, sugar and foam, or layered rate limits.

interface Coffee { double cost(); }
class PlainCoffee implements Coffee { public double cost() { return 2.0; } }
class MilkDecorator implements Coffee {            // wraps a Coffee, adds to it
    private final Coffee inner;
    MilkDecorator(Coffee c) { this.inner = c; }
    public double cost() { return inner.cost() + 0.5; }
}
Enter fullscreen mode Exit fullscreen mode

The trade-off: Decorator avoids a combinatorial explosion of subclasses, at the cost of many small wrapper objects and a stack that can be hard to debug.

A structural diagram of the Strategy and Decorator patterns, showing on one side a context class holding a Strategy interface with three interchangeable algorithm implementations plugged in, and on the other side a Decorator chain where a plain component is wrapped by successive decorators that each share the same interface and add behaviour, illustrating composition over a subclass explosion.

How design patterns show up inside a low-level design round

In a real LLD round you rarely get asked to "name a pattern." Instead, patterns are the solutions you reach for and justify as you build the model:

  • Pricing / tax / discount that varies → Strategy behind an interface (and the open/closed principle in action).
  • A machine or session with distinct modes → State (vending machine, ATM, booking lifecycle) instead of a status flag and a switch.
  • Creating the right subclass from a type → Factory (vehicles, payment methods), keeping new out of the business logic.
  • Several things reacting to an event → Observer (notifications, a live availability board).
  • A single real-world instance → Singleton — used sparingly, and ideally injected rather than hard-wired.
  • Stacking optional features → Decorator (layered limits, add-ons) instead of a subclass per combination.

Say it plainly: I reach for a pattern when it names a problem I actually have — a varying algorithm, a state machine, an event fan-out — and I skip it when a plain method is clearer. Forcing a pattern is as much a design smell as missing one. That judgement, more than the catalogue, is what reads as experience. Design patterns and the SOLID principles are two halves of the same skill — the principles say what good structure looks like, the patterns are the reusable ways to get there.

A diagram mapping design patterns onto moments in a low-level design round, showing varying pricing solved by Strategy, a machine's modes solved by State, subclass creation solved by Factory, an event fan-out solved by Observer, a single real instance solved by Singleton, and stacked features solved by Decorator, each labelled with the problem shape it answers and a note that forcing a pattern is itself a smell.

Low-Level Design
LLD · OOD foundations
Apply the right pattern in a live design round out loud

Practise on Zynter →

How to talk about design patterns in an interview

The probes rhyme across every pattern. Master these and you can defend a design decision in any OOD round.

  • "Which pattern fits here, and why?" → Match the pattern to the problem shape — Strategy for a varying algorithm, State for a state machine, Observer for an event fan-out — and say the requirement it solves, not just the name. (problem solving)
  • "What does this pattern cost you?" → Every pattern adds indirection; name it (a class per algorithm, global state for a Singleton, wrapper objects for a Decorator) so the interviewer sees you weigh it. (communication)
  • "Strategy or just an if/switch?" → Strategy when the variants are real and likely to grow (open/closed); a plain conditional when there are two fixed cases and a pattern would only add ceremony. (problem solving)
  • "How would you test a class that uses a Singleton?" → Acknowledge the difficulty — global state can't be swapped — and prefer injecting a single instance over a hard Singleton where testability matters. (technical execution)
  • "Aren't you over-engineering?" → Apply patterns where change is likely, not everywhere; knowing when a pattern is unnecessary is as much a signal as knowing the pattern. (time management)

Each maps to a debrief dimension. Reading them teaches the answers; it does not teach you to deliver them while someone offers you the simpler option — that only comes from saying them out loud.

How to prepare: a short plan

You do not need all twenty-three patterns. You need the handful that fit interview problems, each with its intent, a tiny example, and its cost.

  • Day 1: Learn the three families and the six that recur — Strategy, Factory, Singleton, Observer, State, Decorator — with a one-sentence intent and a before/after you can write from memory.
  • Day 2: Practise matching patterns to problems (pricing → Strategy, a machine's modes → State, notifications → Observer) and saying each pattern's cost, so you can defend and decline them.
  • Day 3: Do a full LLD problem (parking lot, vending machine) and narrate where each pattern fits and where you deliberately skipped one, timed, with someone offering you a simpler alternative to defend against.

This guide feeds the broader low-level design interview track — patterns are the solutions behind every problem there, so getting the right handful reflexive pays off across all of them.

Low-Level Design
LLD · Core skills
Pick a pattern and defend its cost out loud

Practise on Zynter →

Frequently asked questions

What are design patterns?

Design patterns are named, reusable solutions to problems that recur in object-oriented design. Rather than code you copy, they are templates for how to structure classes and their interactions — so that naming one ("this is a Strategy") communicates an entire design idea in a word. The classic catalogue is the twenty-three Gang of Four patterns, grouped into three families: creational (how objects are made), structural (how they are composed) and behavioral (how they interact). In interviews the value is not reciting the catalogue but recognising which pattern fits a problem, applying it where it earns its keep, and naming its trade-off — and knowing when a plain method is clearer than any pattern.

What is the difference between creational, structural and behavioral patterns?

They are grouped by the kind of problem they solve. Creational patterns deal with object creation — Singleton (one instance), Factory (choosing which class to instantiate), Builder (assembling a complex object step by step) — keeping construction flexible and decoupled from use. Structural patterns deal with composing objects into larger structures — Adapter (making incompatible interfaces work together), Decorator (adding behaviour by wrapping), Facade (a simple front over a complex subsystem), Proxy (a stand-in that controls access). Behavioral patterns deal with how objects interact and divide responsibility — Strategy (interchangeable algorithms), Observer (publish and notify), State (behaviour that changes with state), Command (encapsulating a request). Knowing the family a pattern belongs to helps you reach for the right one.

What is the difference between the Strategy pattern and a simple if/else?

Both choose between behaviours, but Strategy makes that choice extensible and the if/else makes it fixed. With a conditional, every new variant means editing the same method — which violates the open/closed principle and grows into a tangle. With Strategy, each variant is a class implementing a shared interface, chosen at runtime, so a new one is a new class that touches nothing already tested. The judgement is when each is right: if there are two stable cases that will never grow, a plain if/else is clearer and a Strategy is over-engineering; if the variants are real and likely to multiply (pricing rules, rate-limiting algorithms), Strategy pays off. Saying when you would not use Strategy is as strong a signal as knowing it.

Why are interviewers sceptical of the Singleton pattern?

Because a Singleton is global mutable state wearing a pattern's clothes. It guarantees one instance with a global access point, which sounds tidy, but it introduces hidden coupling — any class can reach the Singleton without declaring the dependency — and it makes testing hard, because you cannot swap the single instance for a fake in a unit test. It also has to be made thread-safe, which is easy to get wrong. The pattern is justified when one object genuinely models a single real thing, but the stronger answer in an interview is usually to create a single instance and inject it where it is needed (dependency injection), getting "one instance" without the global-state and testability costs of a hard Singleton.

Which design patterns matter most for a low-level design interview?

Strategy is the most valuable — it solves the "this behaviour varies" problem that appears in almost every LLD (pricing, algorithms, policies) and is the open/closed principle in practice. State is close behind for any problem that is a state machine (vending machine, ATM, booking). Factory handles creating the right subclass from a type, Observer handles event fan-out like notifications or a live display, and Singleton models a single real instance (used sparingly). Decorator is worth knowing for stacking optional behaviours. Together these six cover the large majority of what LLD rounds ask; the other seventeen Gang of Four patterns are good to recognise but rarely the crux.

How do I practise applying design patterns out loud?

Reading the catalogue is not the same as choosing the right pattern — and defending the choice — while an interviewer offers you a simpler option. On Zynter, the low-level design track runs live voice rounds modelled on how real OOD loops run — you write your classes in the editor and a voice interviewer follows up one question at a time ("which pattern fits here?", "what does that Singleton cost you?", "Strategy or just an if/else?"), then gives you a debrief on problem solving, communication, technical execution and time management. The score is a practice signal, not a hiring decision.

Practise it on Zynter

You can name all twenty-three. The round is won on picking the right one — and defending the cost — out loud.

Pick a low-level design round, write your classes in the editor, and defend them out loud to a voice interviewer that keeps asking "which pattern fits here, and why?" and "what does that pattern cost you?" — then read the debrief. Zynter.ai is on-demand mock interviews modelled on real company loops, with 150+ rounds across 20 companies including the low-level design track (Sep 2026).

Practise a low-level design round →
Browse all interview tracks

Top comments (0)