0% found this document useful (0 votes)
25 views9 pages

15 Key Design Patterns - HLD + LLD (Java)

Uploaded by

Aman Gupta
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
25 views9 pages

15 Key Design Patterns - HLD + LLD (Java)

Uploaded by

Aman Gupta
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

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

You might also like