SYSTEM DESIGN MASTERY COURSE TRACK A · LLD · MODULE A6 · WEEKS 9–10 FINAL LLD MODULE
Low-Level Design · Case Studies · All Patterns Applied
LLD CASE
STUDIES
Chess · Elevator · Library · Food Ordering · ATM · Hotel Booking
6
Case Studies
15+
Patterns Used
4
Tasks
1
Capstone
A6
Module
Track A End
Six systems · all Track A patterns appliedCLICK CARD TO DEEP DIVE
01
Chess Game
State · Command · Observer · Factory
Move validation without revealing Board internals. Undo last N moves. Check/checkmate detection by simulation.
02
Elevator System
State · Strategy · Observer · Concurrent
LOOK algorithm. Multiple elevators sharing floor requests. Concurrent calls from many floors simultaneously.
03
Library Management
Builder · Observer · Iterator · Concurrent
Reservation queue per book. Fine calculation. Thread-safe borrowBook() when one copy remains.
04
Food Ordering
Facade · Strategy · Observer · CoR · State
Order lifecycle state machine. Surge pricing. CoR pipeline: validate→price→pay→dispatch→notify.
05
ATM Machine
State · Chain of Resp. · Command · Observer
PIN retry lock. Transaction atomicity. Cash dispensing chain. What if network fails mid-dispense?
06
Hotel Booking
Builder · Strategy · Observer · Concurrent
Concurrent room booking with date-range contention. Dynamic pricing. Reservation waitlist.
Pattern → Problem mapping
SYSTEMKEY PATTERNCONCURRENCY CONCERNKILLER INTERVIEW QUESTION
ChessCommand (move+undo), State (game phase)Single-player — no concurrency"How do you detect checkmate efficiently?"
ElevatorState (per elevator), Strategy (LOOK algo)Concurrent floor requests → ReentrantLock per elevator"How do you handle 1000 floors and 20 elevators?"
LibraryBuilder (Book), Observer (availability)synchronized(book) for last-copy race"Thread safety of borrowBook() when one copy remains?"
Food OrderingCoR (pipeline), State (order lifecycle)Idempotent payment retry, order status updates"How to add a new payment method without touching OrderService?"
ATMState (transaction), CoR (dispensing)ReentrantLock on account debit+dispense atomicity"What happens if network fails after debit but before dispense?"
HotelBuilder (SearchCriteria), Strategy (pricing)ReentrantLock per room for date-range booking"10,000 users try to book the last room simultaneously?"
01Chess
02Elevator
03Library
04Food
05ATM
06Hotel
01
Chess Game
STATE · COMMAND · OBSERVER · FACTORY METHOD
2 players, 8×8 board, 6 piece types. Move validation per piece. Check/checkmate detection by simulation. Undo last N moves. Game state serialization.
WAITING
start
WHITE_TURN
valid move
BLACK_TURN
check
CHECK
no escape
CHECKMATE
Command — Move
Each Move is a Command with execute() + undo(). Stores captured piece + firstMove state for perfect undo. History stack enables N-move rollback.
Factory Method — Piece
PieceFactory.create(type, color, pos) returns correct subclass. Client code never does new King() — decoupled from piece hierarchy.
Observer — Game Events
ChessGame notifies GameObserver on: moveMade, check, checkmate, gameOver. UI and sound engine are observers — completely decoupled.
Move.java — Command pattern with undoJAVA
class Move implements Command {
    private final Piece    piece;
    private final Position from, to;
    private       Piece    capturedPiece;  // Saved for undo
    private       boolean  wasFirstMove;   // Pawn/king special rules

    public void execute(Board board) {
        capturedPiece = board.getPiece(to);
        wasFirstMove  = piece.isFirstMove();
        board.setPiece(to, piece);  board.setPiece(from, null);
        piece.setPosition(to);     piece.setFirstMove(false);
    }

    public void undo(Board board) {
        board.setPiece(from, piece);          // Restore moving piece
        board.setPiece(to, capturedPiece);     // Restore captured piece (null if none)
        piece.setPosition(from);
        piece.setFirstMove(wasFirstMove);
    }
}

// Checkmate detection — simulate all moves, check none escape check
public boolean isCheckmate(Board board, PieceColor color) {
    if (!isCheck(board, color)) return false;
    return getAllPieces(board, color).stream()
        .flatMap(p -> p.validMoves(board).stream()
            .map(to -> new Move(p, p.getPosition(), to)))
        .noneMatch(m -> !wouldLeaveKingInCheck(m, board, color));
}
02
Elevator System
STATE · STRATEGY (LOOK) · OBSERVER · CONCURRENT
N elevators, M floors. LOOK algorithm (sweep up then down). Concurrent floor requests. Pluggable selection strategy for different scheduling algorithms.
IDLE
request
MOVING_UP
floor reached
STOPPED_OPEN
no more up
MOVING_DOWN
done
IDLE
State — per Elevator
Each elevator holds a state (IDLE/MOVING_UP/MOVING_DOWN/STOPPED). step() transitions automatically. No giant switch statement.
Strategy — Scheduling
ElevatorSelectionStrategy is injected into ElevatorController. Swap LOOK for FCFS or zone-based strategy without changing controller.
Concurrency — ReentrantLock
Each Elevator has its own ReentrantLock. addRequest() and step() are both synchronized per elevator — no contention between elevators.
Elevator.java — LOOK algorithm + concurrent requestsJAVA
class Elevator {
    private final TreeSet<Integer> upRequests   = new TreeSet<>();
    private final TreeSet<Integer> downRequests = new TreeSet<>(Comparator.reverseOrder());
    private final ReentrantLock  lock = new ReentrantLock();
    private       ElevatorState  state = ElevatorState.IDLE;
    private int                   currentFloor = 1;

    // LOOK: service all requests in current direction, then reverse
    public void step() {
        lock.lock();
        try {
            switch (state) {
                case MOVING_UP -> {
                    if (!upRequests.isEmpty()) {
                        currentFloor = upRequests.first();  // next floor up
                        upRequests.remove(currentFloor);
                        state = ElevatorState.STOPPED_OPEN;
                    } else if (!downRequests.isEmpty()) {
                        state = ElevatorState.MOVING_DOWN;  // reverse
                    } else { state = ElevatorState.IDLE; }
                }
                /* ... MOVING_DOWN, STOPPED_OPEN, IDLE cases ... */
            }
        } finally { lock.unlock(); }
    }
}
03
Library Management
BUILDER · OBSERVER · ITERATOR · CONCURRENCY
Book catalog, member management, borrowing/returning with fine calculation. Reservation queue notifies next member when book becomes available.
Builder — Book
Book has many optional attributes (genre, publisher, year). Builder prevents telescoping constructors and makes required fields explicit.
Observer — Availability
returnBook() triggers notification to next member in reservation queue. LibraryObserver decouples notification mechanism from core borrow logic.
Concurrency
synchronized(book) for last-copy race condition. ConcurrentLinkedQueue for reservation queue — safe concurrent enqueue/dequeue.
LibrarySystem.java — thread-safe last copy borrowingJAVA
public boolean borrowBook(String isbn, Member member) {
    Book book = catalog.get(isbn);
    if (book == null) throw new BookNotFoundException(isbn);

    if (book.getAvailable() == 0) {
        reservations.reserve(book, member);  // Join waitlist
        return false;
    }

    // Synchronize on book object — prevents two threads taking last copy
    synchronized (book) {
        if (book.getAvailable() == 0) {  // Double-check after sync
            reservations.reserve(book, member);
            return false;
        }
        book.decrementAvailable();
    }
    activeBorrow.put(member.id+":"+isbn, new Borrowing(book, member));
    return true;
}

public void returnBook(String isbn, Member member) {
    Borrowing b = activeBorrow.remove(member.id+":"+isbn);
    b.markReturned();
    synchronized (b.getBook()) { b.getBook().incrementAvailable(); }
    // Notify next in queue
    reservations.nextInQueue(book).ifPresent(next ->
        observers.forEach(o -> o.onBookAvailable(book, next)));
}
04
Online Food Ordering
FACADE · STRATEGY · OBSERVER · CHAIN OF RESPONSIBILITY · STATE
Complete order lifecycle state machine. Surge pricing strategy. CoR processing pipeline: validate → price → payment → delivery assignment → notification.
PLACED
ACCEPTED
PREPARING
READY
PICKED_UP
DELIVERED
OrderService.java — CoR pipeline + StrategyJAVA
// Chain: Validation → Payment → Delivery → Notification
OrderHandler chain = new ValidationHandler();
chain.setNext(new PaymentHandler(paymentService))
     .setNext(new DeliveryAssignmentHandler(deliveryService))
     .setNext(new NotificationHandler(notifier));

// STRATEGY: surge pricing (pluggable at runtime)
class SurgePricingStrategy implements PricingStrategy {
    public double calculateTotal(Order order) {
        double base  = order.getItems().stream().mapToDouble(Item::getPrice).sum();
        double surge = isPeakHour(order.getTime()) ? 1.3 : 1.0;
        return base * surge + DELIVERY_FEE;
    }
}

// Add new payment method: new class implementing PaymentHandler
// No changes to ValidationHandler, DeliveryHandler, NotificationHandler (OCP)
05
ATM Machine
STATE · CHAIN OF RESPONSIBILITY · COMMAND · OBSERVER
PIN retry lockout, transaction atomicity, cash dispensing via CoR. Command enables transaction reversal if dispense fails after debit.
IDLE
insert card
CARD_IN
correct PIN
AUTH
select txn
TXN_SELECTED
dispense
COMPLETE
ATM — PIN retry + transaction atomicityJAVA
// PIN retry: 3 attempts then card retained
class CardInsertedState implements ATMState {
    private int attempts = 0;

    public void enterPin(ATM atm, String pin) {
        if (atm.getBank().verifyPin(atm.getCurrentCard(), pin)) {
            atm.setState(new AuthenticatedState());
        } else if (++attempts >= 3) {
            atm.getCardReader().retainCard();  // Swallow card
            atm.setState(new IdleState());
            atm.display("Card retained — 3 failed attempts");
        }
    }
}

// Transaction atomicity: debit then dispense
// If dispense fails → undo() credits account back
class WithdrawalCommand implements Command {
    public void execute() {
        account.debit(amount);   // 1. Debit
        dispenser.dispense(amount); // 2. Dispense (may fail)
    }
    public void undo() {
        account.credit(amount);  // Reversal if dispense failed
        logReversal(transactionId);
    }
}
06
Hotel Booking System
BUILDER · STRATEGY · OBSERVER · CONCURRENCY
Concurrent room booking with date-range contention. Dynamic pricing (weekend/occupancy surge). Reservation waitlist with Observer notification.
Room.java — thread-safe date-range bookingJAVA
class Room {
    private final ReentrantLock lock       = new ReentrantLock();
    private final Set<LocalDate> booked    = new HashSet<>();

    public boolean tryBook(LocalDate in, LocalDate out) {
        lock.lock();
        try {
            List<LocalDate> dates = in.datesUntil(out).collect(toList());
            if (dates.stream().anyMatch(booked::contains)) return false;
            booked.addAll(dates);  return true;
        } finally { lock.unlock(); }
    }
}

// Dynamic pricing strategy
class DynamicPricingStrategy implements PricingStrategy {
    public double getPrice(Room room, LocalDate date, int occupancy) {
        double base = room.getBasePrice();
        if (date.getDayOfWeek() == DayOfWeek.FRIDAY
                || date.getDayOfWeek() == DayOfWeek.SATURDAY) base *= 1.2;
        if      (occupancy > 80) base *= 1.5;
        else if (occupancy > 60) base *= 1.2;
        return base;
    }
}
5-step LLD interview framework
THE 5-STEP LLD FRAMEWORK — USE FOR EVERY INTERVIEW
01
CLARIFY (3 min)
Who are users? What are core use cases? Single machine or distributed? Any specific NFRs (concurrency, scale)? Don't assume — ask.
02
ENTITIES (5 min)
List 5–8 core nouns from requirements. Define key attributes and relationships. Draw a simple entity diagram. Avoid over-modelling at this stage.
03
DESIGN (15 min)
Interface first, implementation second. Identify patterns and justify WHY. Don't use a pattern unless it solves a real problem. Explain trade-offs aloud.
04
EDGE CASES (5 min)
Concurrency: which operations need thread safety? Error states: failure recovery? Validation: where is input validated? What are the invariants?
05
CODE (15 min)
Focus on the most interesting class. Show you understand the pattern — don't just write boilerplate. Verbalize trade-offs. Time-box ruthlessly.
Killer questions + strong answers
SYSTEMKILLER QUESTIONSTRONG ANSWER
Chess"How do you detect checkmate?"Simulate every legal move for the player in check. If none escape check → checkmate. Key: simulate-check-undo via Command pattern.
Elevator"Handle 1000 floors efficiently?"TreeSet for requests (O(log n) insert/min). LOOK direction reversal. Per-elevator locking prevents cross-elevator contention.
Library"Thread safety of last copy?"synchronized(book) with double-check. ConcurrentLinkedQueue for reservation. Synchronized block is on the specific book — not the entire catalog.
Food Ordering"Add new payment method?"New class implementing PaymentHandler. Set it in the chain. Zero changes to ValidationHandler, DeliveryHandler. OCP via CoR.
ATM"Network fails after debit, before dispense?"WithdrawalCommand.undo() credits account back. Transaction ID logged for idempotent replay. Same-transaction retry is safe.
Hotel"10,000 concurrent bookings for last room?"ReentrantLock per room. tryBook() is atomic. Losers get waitlisted via reservation queue. Observer notifies when room cancels.
Common LLD anti-patterns — avoid these in interviews
🧱
God Class
One class does everything — BookingService has 2000 lines handling payment, notifications, seat locking, pricing, emails. Violates SRP. Fix: split into focused services behind a Facade.
🏚️
Anemic Domain Model
Entities are pure data bags (only getters/setters). All logic lives in service classes. Result: procedural code disguised as OOP. Fix: move behaviour to entities — Order.cancel(), Seat.lock(), Booking.getFee().
🔧
Over-Engineering
Using every design pattern you know regardless of need. A simple CRUD system with Factory + Builder + Strategy + Observer + Decorator is a red flag. Fix: use a pattern only when it solves a concrete problem.
🔗
No Interfaces
Every class references concrete types: PaymentService uses new StripeGateway() directly. Kills OCP, testability, and swappability. Fix: all dependencies injected via interfaces.
Ignoring Concurrency
"I'll add thread safety later." In interviews, the concurrency question IS the design question. Fix: identify shared mutable state upfront, choose the right primitive (atomic vs lock vs semaphore).
🔓
Exposing Internals
getBoard()[row][col] = piece — letting clients mutate internal structures. Breaks encapsulation, makes validation impossible. Fix: expose behaviour methods (makeMove, isValidMove) not raw data.
🗺️
Validation Scattered Everywhere
if (seat != null && !seat.isBooked() && user != null && ...) in 12 different places. Fix: single Validator class per domain object. Or CoR where ValidationHandler is one step.
📋
Missing Invariants
No thought given to what must always be true: "available + occupied == total", "seat has at most one booking", "balance never goes negative". Fix: state invariants explicitly; enforce in synchronized/locked sections.
// PATTERN SELECTION CHEAT SHEET
if/else on algorithm type → Strategy
Need undo/redo → Command
Object behaves differently per mode → State
One change → many notifications → Observer
Multiple handlers, unknown upfront → CoR
Simplify complex subsystem → Facade
Many optional constructor params → Builder
Limit concurrent access (N slots) → Semaphore
Incompatible interface → Adapter
Add behaviour without subclassing → Decorator
Tree structure, uniform ops → Composite
Read-heavy shared data → ReadWriteLock
01
Snake and Ladder Game
~3 hrs · full LLD
Design Snake and Ladder:
  - N players, 100-cell board, configurable snakes/ladders
  - Dice rolling: pluggable strategy (single die, two dice, biased die)
  - Special cells: snake head slides down, ladder bottom climbs up
  - Win condition: exactly 100 (overshoot = no move)
  - Multiplayer: track current player
  - Save/load game state (Memento)

Required patterns:
  Factory:   Dice creation
  Strategy:  Dice rolling algorithm
  Observer:  onPlayerMoved, onSnakeBite, onLadderClimb, onWin
  Command:   Move (with undo for "take back" variant)
  Memento:   Save game state to resume later

Deliver: Full Java + UML + test for 4 players, 10-round game
02
Parking Lot V2 — Extensions
~2.5 hrs · extend A5
Extend the A5 Parking Lot with:
  - Monthly pass holders: reserved spots, no time-based fee
  - EV charging spots: AVAILABLE → CHARGING → CHARGED → AVAILABLE
  - VIP spots: premium pricing, observer notification on availability
  - Smart fee:
      < 30 min:  flat ₹20
      < 2 hours: flat ₹50
      > 2 hours: ₹80/hour after first 2h
  - Multiple entry/exit gates (separate rate limiters per gate)
  - Daily revenue report: thread-safe aggregation

Design challenge: adding EV state without breaking existing Spot hierarchy.
Show OCP — new spot type = new class, existing code unchanged.
03
Multi-Level Cache System
~3 hrs · code
Design a three-level cache:
  L1: In-process LRU (1,000 items, O(1) get/put)
  L2: Distributed (Redis-like, 100,000 items, TTL-based eviction)
  L3: Database (unlimited, slowest)

On get(key):
  Hit L1 → return immediately
  Miss L1, hit L2 → populate L1, return
  Miss L2, hit L3 → populate L2 + L1, return
  Miss all → return null

Write policies (Strategy, pluggable):
  write-through:  write all levels synchronously
  write-back:     write L1 only; async flush to L2/L3
  write-around:   bypass cache; write directly to L3

Concurrency: ReadWriteLock per level (reads don't block each other)
Invalidation: CacheInvalidationEvent via Observer pattern

Test: cache hit rates, concurrency safety, write policy correctness
Capstone — BookMyShow (Full Track A)
~8 hrs · complete LLD
Entities: Movie, Show, Screen, Seat, Booking, User, Theatre, Payment, Ticket

Features:
  1. Browse movies by city/date
  2. Select show → choose seats → pay → receive ticket
  3. Seat hold expires after 5 minutes if unpaid
  4. Concurrent seat selection — no double booking
  5. Pricing: weekday/weekend × screen type × seat type multipliers
  6. Cancellation: full refund >24h, 50% refund 2–24h, none <2h
  7. Notifications: booking confirmation, 2h-before show reminder

All 9 patterns with justification:
  State:    Seat (AVAILABLE/LOCKED/BOOKED/CANCELLED)
  Observer: Booking events, seat expiry alerts
  Command:  BookSeat + CancelBooking with undo/refund
  Strategy: Pricing engine (multipliers per category)
  CoR:      validate → price → payment → confirm → notify
  Facade:   BookingService.bookSeats(userId, showId, seatIds)
  Builder:  BookingRequest (optional fields: promo code, special needs)
  Factory:  TicketFactory (standard vs IMAX vs 4DX ticket format)
  Concurrency: ReentrantLock per Seat + ScheduledExecutor for 5-min expiry

Deliverables:
  1. Complete Java implementation (every class)
  2. UML class diagram with all 9 patterns annotated
  3. Sequence diagram: "User books 2 IMAX seats" happy path
  4. JUnit test: 20 threads try to book last 3 seats — zero double bookings
0 / 12 completedMODULE A6 · TRACK A FINAL
Can design Chess Game — move validation, undo, checkmate detection
Can design Elevator — LOOK algorithm, concurrent requests, pluggable strategy
Can design Library — reservation queue, fine calc, thread-safe last copy
Can design Food Ordering — CoR pipeline, surge pricing, order state machine
Can design ATM — PIN retry, transaction atomicity, Command undo
Can design Hotel Booking — concurrent date-range locking, dynamic pricing
Know the 5-step LLD interview framework by heart
Can recite pattern selection cheat sheet (12 patterns → triggers)
✏️ Task 1: Snake & Ladder — all 5 patterns + game state save/load
✏️ Task 2: Parking Lot V2 — EV spots, monthly pass, multi-gate
✏️ Task 3: Multi-Level Cache — 3 levels, 3 write policies, concurrent
✏️ Capstone: BookMyShow — 9 patterns, concurrency proof, UML, sequence diagram
TRACK A COMPLETE
🎉 Ready for Track B
B1 · HLD Fundamentals — CAP theorem, consistency models, availability
B2 · Databases at Scale — sharding, replication, SQL vs NoSQL
B3 · Caching — Redis, CDN, cache invalidation strategies
B4 · Message Queues — Kafka, RabbitMQ, event streaming
B5 · URL Shortener · Pastebin · TinyURL
B6–B10 · Twitter · Netflix · Uber · WhatsApp · Google Drive
← PREVIOUS: LLD A5 📄 READ STUDY NOTES ↑ ROADMAP NEXT: HLD B1 →