STUDIES
| SYSTEM | KEY PATTERN | CONCURRENCY CONCERN | KILLER INTERVIEW QUESTION |
|---|---|---|---|
| Chess | Command (move+undo), State (game phase) | Single-player — no concurrency | "How do you detect checkmate efficiently?" |
| Elevator | State (per elevator), Strategy (LOOK algo) | Concurrent floor requests → ReentrantLock per elevator | "How do you handle 1000 floors and 20 elevators?" |
| Library | Builder (Book), Observer (availability) | synchronized(book) for last-copy race | "Thread safety of borrowBook() when one copy remains?" |
| Food Ordering | CoR (pipeline), State (order lifecycle) | Idempotent payment retry, order status updates | "How to add a new payment method without touching OrderService?" |
| ATM | State (transaction), CoR (dispensing) | ReentrantLock on account debit+dispense atomicity | "What happens if network fails after debit but before dispense?" |
| Hotel | Builder (SearchCriteria), Strategy (pricing) | ReentrantLock per room for date-range booking | "10,000 users try to book the last room simultaneously?" |
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));
}
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(); }
}
}
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)));
}
// 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)
// 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);
}
}
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;
}
}
| SYSTEM | KILLER QUESTION | STRONG 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. |
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
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.
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
Entities: Movie, Show, Screen, Seat, Booking, User, Theatre, Payment, TicketFeatures:
- Browse movies by city/date
- Select show → choose seats → pay → receive ticket
- Seat hold expires after 5 minutes if unpaid
- Concurrent seat selection — no double booking
- Pricing: weekday/weekend × screen type × seat type multipliers
- Cancellation: full refund >24h, 50% refund 2–24h, none <2h
- 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:
- Complete Java implementation (every class)
- UML class diagram with all 9 patterns annotated
- Sequence diagram: “User books 2 IMAX seats” happy path
- JUnit test: 20 threads try to book last 3 seats — zero double bookings
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
function goCase(i) { show(‘cases’, document.querySelectorAll(‘.nav-tab’)[1]); selCase(i); }
function tt(hd) { const bd = hd.nextElementSibling; const arr = hd.querySelector(‘.t-arr’); const open = bd.classList.contains(‘open’); bd.classList.toggle(‘open’, !open); arr.classList.toggle(‘open’, !open); }
function tick(el) {
el.classList.toggle(‘done’);
el.querySelector(‘.chk-box’).textContent = el.classList.contains(‘done’) ? ’✓’ : ”;
const total = document.querySelectorAll(‘.chk’).length;
const done = document.querySelectorAll(‘.chk.done’).length;
document.getElementById(‘prog-lbl’).textContent = ${done} / ${total} completed;
document.getElementById(‘prog-fill’).style.width = ${(done/total)*100}%;
}