15 Key Design Patterns — HLD + LLD (Java)
Goal: A compact, interview-focused, practical reference covering the most common
design patterns used in projects and daily life. For each pattern you’ll find:
• HLD (What/When + tiny ASCII diagram) — system-level view (who calls whom)
• LLD (roles/classes + concise Java example) — class-level sketch you can code
• Step-by-step checklist to implement
• Practical project uses & daily-life analogy
• Interview tip (how to answer fast in 4 lines)
How to read this doc — where is HLD and where is LLD
• HLD: short sentence + ASCII diagram right after the pattern name — shows
components/modules and their interactions. Use this when explaining architecture
to managers or during system-design parts of interviews.
• LLD: Java code + bullet list of classes and responsibilities — use this for coding
questions or whiteboard/class-level design.
CREATIONAL PATTERNS
1) Singleton
HLD (what/when): one shared instance across the app (config, logger, connection pool).
[Clients] -> [Singleton Instance]
LLD (roles / Java): Logger (private ctor, volatile instance, getInstance()).
public class Logger {
private static volatile Logger inst;
private Logger(){}
public static Logger getInstance(){
if(inst==null){ synchronized(Logger.class){ if(inst==null) inst=new Logge
r(); }}
return inst;
}
public void log(String m){ System.out.println(m); }
}
Steps: 1) private constructor 2) private static instance 3) thread-safe accessor 4) prevent
cloning/serialization if needed Uses & analogy: DB pool, config service. Analogy: only one
president.
Interview tip: mention lazy vs eager and thread-safety.
2) Factory Method
HLD: choose product at runtime via subclass creator.
[Client] -> [Creator.create()] -> [ConcreteProductA | ConcreteProductB]
LLD (roles / Java): Creator (abstract create), Product (interface), ConcreteProducts.
abstract class Dialog{ abstract Button createButton(); void render(){ Button
b=createButton(); b.click(); }}
class WindowsDialog extends Dialog{ Button createButton(){ return new Windows
Button(); }}
interface Button{ void click(); }
Steps: 1) define Product interface 2) implement concrete products 3) add Creator with
factory method 4) client uses Creator Uses & analogy: Payment gateway selection, report
generators. Analogy: coffee machine selecting type. Interview tip: contrast with Simple
Factory and Abstract Factory.
3) Abstract Factory
HLD: family of related products for a platform.
[Client] -> [AbstractFactory] -> [Button / Checkbox implementations per platf
orm]
LLD (roles / Java): GUIFactory (interface), Button/Checkbox, WinFactory/MacFactory.
interface GUIFactory{ Button createButton(); Checkbox createCheckbox(); }
class WinFactory implements GUIFactory{ public Button createButton(){ return
new WinButton(); } public Checkbox createCheckbox(){ return new WinCheckbox()
; }}
Steps: 1) define abstract factory interface 2) define product family interfaces 3) implement
concrete factories for each family 4) client uses factory chosen at startup Uses & analogy:
cross-platform UI kits. Analogy: furniture factory making matching chair+table. Interview
tip: say it guarantees product compatibility.
4) Builder
HLD: step-by-step object construction when many optional params.
[Client] -> [Builder] -> [Product]
LLD (roles / Java): Product (immutable), Builder (fluent setters + build()).
class User{ private final String name; private final String phone; private Us
er(Builder b){name=b.name; phone=b.phone;} public static class Builder{ Strin
g name; String phone; Builder name(String n){this.name=n; return this;} Build
er phone(String p){this.phone=p; return this;} User build(){return new User(t
his);} }}
Steps: 1) private Product ctor 2) expose Builder 3) fluent setters returning builder 4)
validate in build() Uses & analogy: HTTP requests, DTOs, complex domain objects.
Analogy: assembling a burger. Interview tip: emphasize immutability and readability.
5) Prototype
HLD: clone an existing object instance to save construction cost.
[Client] -> clone() -> [New Instance]
LLD (roles / Java): Prototype interface or Cloneable implementation, optional prototype
registry.
class Config implements Cloneable{ Map<String,String> map; public Config clon
e(){ try{ return (Config)super.clone(); }catch(CloneNotSupportedException e){
throw new RuntimeException(e);} }}
Steps: 1) implement clone() carefully 2) decide deep vs shallow copy 3) use registry for
prototypes 4) clone+mutate for variations Uses & analogy: environment templates,
expensive object graphs. Analogy: photocopying a document. Interview tip: explain deep
copy pitfalls.
STRUCTURAL PATTERNS
6) Adapter
HLD: adapt old interface to new expectations.
[Client] -> [Target] <- Adapter -> [Adaptee]
LLD (roles / Java): Target (expected), Adaptee (existing), Adapter (implements Target,
delegates to Adaptee).
interface Bird{ void quack(); void fly(); }
class Turkey{ void gobble(){ System.out.println("gobble"); }}
class TurkeyAdapter implements Bird{ private final Turkey t; TurkeyAdapter(Tu
rkey t){this.t=t;} public void quack(){ t.gobble(); } public void fly(){ /* e
mulate */ }}
Steps: 1) identify Target 2) wrap Adaptee in Adapter 3) translate calls 4) test edge cases
Uses & analogy: legacy API integration. Analogy: travel plug adapter. Interview tip: clarify
object vs class adapter (inheritance vs composition).
7) Decorator
HLD: attach extra responsibilities at runtime by wrapping.
[Client] -> [Decorator] -> [Component]
LLD (roles / Java): Component, ConcreteComponent, Decorator (has a Component),
ConcreteDecorators.
interface Coffee{ double cost(); }
class SimpleCoffee implements Coffee{ public double cost(){ return 5; } }
abstract class CoffeeDecorator implements Coffee{ protected Coffee c; CoffeeD
ecorator(Coffee c){this.c=c;} }
class Milk extends CoffeeDecorator{ Milk(Coffee c){super(c);} public double c
ost(){ return c.cost()+1; }}
Steps: 1) design Component interface 2) implement base component 3) implement
decorators delegating to wrapped object 4) chain decorators Uses & analogy: I/O streams,
adding features. Analogy: adding pizza toppings. Interview tip: show how it avoids
explosion of subclasses.
8) Proxy
HLD: control access to another object (lazy, caching, security).
[Client] -> [Proxy] -> [RealSubject]
LLD (roles / Java): Subject interface, RealSubject, Proxy (adds caching/authorization).
interface Image{ void display(); }
class RealImage implements Image{ String file; RealImage(String f){file=f; lo
ad();} void load(){/*heavy*/} public void display(){ System.out.println("disp
lay "+file);} }
class ImageProxy implements Image{ RealImage real; String file; ImageProxy(St
ring f){file=f;} public void display(){ if(real==null) real=new RealImage(fil
e); real.display(); }}
Steps: 1) define Subject interface 2) implement RealSubject 3) implement Proxy adding
behavior 4) clients use Subject reference Uses & analogy: caching DB queries, remote
proxies. Analogy: secretary handling calls for boss. Interview tip: explain difference
between Decorator vs Proxy: proxy controls access, decorator adds behavior.
9) Facade
HLD: simplify a complex subsystem with a single entry point.
[Client] -> [Facade] -> [Subsystem A/B/C]
LLD (roles / Java): Facade exposes easy API, internally delegates to many subsystems.
class BookingFacade{ PaymentService pay; InventoryService inv; NotificationSe
rvice note; public void book(Order o){ inv.reserve(o); pay.charge(o); note.no
tify(o); }}
Steps: 1) identify frequent use-cases 2) implement Facade methods that orchestrate
subsystems 3) keep subsystems decoupled 4) expose minimal API Uses & analogy: SDK
entry points, aggregators. Analogy: hotel receptionist. Interview tip: stress simplification
and decoupling.
10) Composite
HLD: tree of objects treated uniformly.
[Component] -> Leaf | Composite(children -> Component*)
LLD (roles / Java): Component interface, Leaf, Composite (List children).
interface Component{ void render(); }
class Leaf implements Component{ public void render(){ System.out.println("le
af"); }}
class Composite implements Component{ List<Component> c=new ArrayList<>(); vo
id add(Component x){c.add(x);} public void render(){ c.forEach(Component::ren
der); }}
Steps: 1) define uniform interface 2) implement leaf 3) implement composite with child
management 4) recursion for operations Uses & analogy: UI trees, file systems. Analogy:
folders & files. Interview tip: show traversal (pre/post order) and avoid exposing internals.
BEHAVIORAL PATTERNS
11) Strategy
HLD: Interchangeable algorithms at runtime.
[Context] -> uses -> [Strategy] -> [ConcreteStrategies]
LLD (roles / Java): Strategy interface, ConcreteStrategies, Context (holds strategy).
interface Discount { double apply(double price); }
class FestiveDiscount implements Discount {
public double apply(double p) { return p * 0.9; }
}
class Checkout {
Discount d;
Checkout(Discount d) { this.d = d; }
double finalPrice(double p) { return d.apply(p); }
}
Steps:
1. Define Strategy interface
2. Implement multiple algorithms
3. Inject strategy into context
4. Swap strategies for different behavior
Uses & Analogy: Payment, sorting, routing. Analogy: choosing different routes. Interview
Tip: Emphasize OCP — new strategy added without changing context.
12) Observer
HLD: Subject notifies many observers on state change.
[Subject] -> notify -> [Observers...]
LLD (roles / Java): Subject with register/remove/notify, Observer with update().
interface Observer { void update(String evt); }
class Subject {
List<Observer> obs = new ArrayList<>();
void register(Observer o) { obs.add(o); }
void notifyAll(String e) { obs.forEach(o -> o.update(e)); }
}
Steps:
1. Design notification model
2. Implement registration
3. Call notify on state change
4. Consider async/event queues for scale
Uses & Analogy: Event buses, UI updates. Analogy: YouTube subscriptions. Interview Tip:
Discuss memory leaks (unregister unused observers).
13) Template Method
HLD: Define skeleton of an algorithm, let subclasses fill steps.
[AbstractClass] -> defines -> [TemplateMethod] -> calls -> [PrimitiveOperatio
ns]
LLD (roles / Java): Abstract class with template method, concrete subclasses override
steps.
abstract class DataParser {
public final void parseData() {
readData();
processData();
saveData();
}
abstract void readData();
abstract void processData();
abstract void saveData();
}
Steps:
1. Create abstract class with template method
2. Keep invariant steps fixed
3. Let subclasses override specific steps
Uses & Analogy: File parsing, algorithm frameworks. Analogy: recipe template with
customizable steps. Interview Tip: Mention control over algorithm flow.
14) Command
HLD: Encapsulate a request as an object.
[Invoker] -> calls -> [Command] -> executes -> [Receiver]
LLD (roles / Java): Command interface, concrete commands, invoker, receiver.
interface Command { void execute(); }
class LightOnCommand implements Command {
Light light;
LightOnCommand(Light light) { this.light = light; }
public void execute() { light.on(); }
}
class RemoteControl {
Command cmd;
void setCommand(Command cmd) { this.cmd = cmd; }
void pressButton() { cmd.execute(); }
}
Steps:
1. Define Command interface
2. Implement concrete commands
3. Set command in invoker
4. Execute without knowing receiver details
Uses & Analogy: Undo/redo, task queues. Analogy: waiter taking orders. Interview Tip:
Emphasize decoupling of sender and receiver.
15) Chain of Responsibility
HLD: Pass request along a chain until handled.
[Handler1] -> [Handler2] -> [Handler3] ...
LLD (roles / Java): Abstract handler, concrete handlers, setNext for chain.
abstract class Handler {
Handler next;
void setNext(Handler next) { this.next = next; }
abstract void handle(String req);
}
class AuthHandler extends Handler {
void handle(String req) {
if (req.equals("auth")) System.out.println("Auth OK");
else if (next != null) next.handle(req);
}
}
Steps:
1. Create handler interface/abstract class
2. Implement concrete handlers
3. Link handlers in sequence
4. Pass request until handled or end of chain
Uses & Analogy: Middleware, support escalation. Analogy: customer service escalation.
Interview Tip: Mention flexibility in adding/removing handlers.
Thankyou
Ashish Thakur