Requirements
Let's define the functional and non-functional requirements for a parking lot system.
Functional Requirements
1. Support multiple vehicle types:
- Motorcycle, Car, Truck
2. Multiple floors with parking spots:
- Each floor has different spot types
- Spot types: Compact, Regular, Large
3. Vehicle entry/exit:
- Ticket issued on entry
- Payment processed on exit
4. Parking spot allocation:
- Assign appropriate spot for vehicle type
- Track available spots per floor
5. Pricing:
- Different rates per vehicle type
- Time-based pricing
6. Display boards:
- Show available spots per floor
- Show total available spots
Non-Functional Requirements
1. Concurrency: Multiple entry/exit panels simultaneously
2. Scalability: Support 1000s of vehicles
3. Availability: 99.9% uptime
4. Real-time: Spot availability updated immediately
Core Entities
Vehicle, ParkingSpot, ParkingFloor, ParkingLot,
Ticket, Payment, VehicleType, SpotType
Key Workflows
Entry Flow:
Vehicle arrives → Select vehicle type → Check availability
→ Allocate spot → Issue ticket → Open gate → Vehicle enters
Exit Flow:
Vehicle at gate → Scan ticket → Calculate duration
→ Calculate fee → Process payment → Release spot → Open gate
Class Design
Let's design the classes and their relationships.
Class Diagram
┌──────────────────────────────────────────────┐
│ ParkingLot (Singleton) │
├──────────────────────────────────────────────┤
│ - floors: List<ParkingFloor> │
│ - displayBoard: DisplayBoard │
├──────────────────────────────────────────────┤
│ + getParkingSpot(type): ParkingSpot │
│ + releaseSpot(spot): void │
│ + getAvailableSpots(): int │
└──────────────────────────────────────────────┘
│ 1
│ has many
▼ *
┌──────────────────────────────────────────────┐
│ ParkingFloor │
├──────────────────────────────────────────────┤
│ - floorNumber: int │
│ - spots: List<ParkingSpot> │
│ - displayBoard: DisplayBoard │
├──────────────────────────────────────────────┤
│ + getAvailableSpot(type): ParkingSpot │
│ + getAvailableCount(type): int │
└──────────────────────────────────────────────┘
│ 1
│ has many
▼ *
┌──────────────────────────────────────────────┐
│ ParkingSpot │
├──────────────────────────────────────────────┤
│ - spotNumber: String │
│ - spotType: SpotType │
│ - vehicle: Vehicle (nullable) │
│ - isOccupied: boolean │
├──────────────────────────────────────────────┤
│ + park(vehicle): boolean │
│ + remove(): Vehicle │
│ + isAvailableFor(type): boolean │
└──────────────────────────────────────────────┘
┌──────────────────────────────────────────────┐
│ Vehicle │
├──────────────────────────────────────────────┤
│ - licensePlate: String │
│ - type: VehicleType │
│ - ticket: Ticket (nullable) │
├──────────────────────────────────────────────┤
│ + getType(): VehicleType │
│ + getLicensePlate(): String │
└──────────────────────────────────────────────┘
Enums
public enum VehicleType {
MOTORCYCLE, CAR, TRUCK
}
public enum SpotType {
COMPACT, REGULAR, LARGE
}
public enum PaymentStatus {
PENDING, COMPLETED, FAILED
}
Vehicle-Spot Mapping
VehicleType → Required SpotType
MOTORCYCLE → COMPACT (or larger)
CAR → REGULAR (or larger)
TRUCK → LARGE only
Hierarchy: COMPACT < REGULAR < LARGE
Implementation
Key implementation details for the parking lot system.
ParkingLot Singleton
public class ParkingLot {
private static ParkingLot instance;
private List<ParkingFloor> floors;
private ParkingLot() {
this.floors = new ArrayList<>();
}
public static synchronized ParkingLot getInstance() {
if (instance == null) {
instance = new ParkingLot();
}
return instance;
}
public ParkingSpot findSpot(VehicleType type) {
for (ParkingFloor floor : floors) {
ParkingSpot spot = floor.getAvailableSpot(type);
if (spot != null) {
return spot;
}
}
return null; // No spot available
}
}
ParkingSpot with Strategy
public class ParkingSpot {
private final String spotNumber;
private final SpotType spotType;
private Vehicle vehicle;
public boolean canFit(VehicleType vehicleType) {
return spotType.canFit(vehicleType);
}
public boolean park(Vehicle vehicle) {
if (!canFit(vehicle.getType()) || vehicle != null) {
return false;
}
this.vehicle = vehicle;
return true;
}
public Vehicle remove() {
Vehicle v = this.vehicle;
this.vehicle = null;
return v;
}
}
Ticket System
public class Ticket {
private final String ticketId;
private final Vehicle vehicle;
private final ParkingSpot spot;
private final LocalDateTime entryTime;
private LocalDateTime exitTime;
public Ticket(Vehicle vehicle, ParkingSpot spot) {
this.ticketId = UUID.randomUUID().toString();
this.vehicle = vehicle;
this.spot = spot;
this.entryTime = LocalDateTime.now();
}
public Money calculateFee(PricingStrategy pricing) {
long hours = Duration.between(entryTime,
exitTime != null ? exitTime : LocalDateTime.now()).toHours();
return pricing.calculate(vehicle.getType(), hours);
}
}
Pricing Strategy
public interface PricingStrategy {
Money calculate(VehicleType type, long hours);
}
public class HourlyPricing implements PricingStrategy {
private static final Map<VehicleType, Money> RATES = Map.of(
VehicleType.MOTORCYCLE, new Money(2, "USD"),
VehicleType.CAR, new Money(5, "USD"),
VehicleType.TRUCK, new Money(10, "USD")
);
public Money calculate(VehicleType type, long hours) {
return RATES.get(type).multiply(hours);
}
}
Follow-ups
Common follow-up questions and extensions.
Follow-up Questions
1. How to handle multiple entry/exit points?
→ Each panel communicates with central ParkingLot
→ Use thread-safe data structures
2. How to handle payment processing?
→ PaymentProcessor interface with multiple implementations
→ Cash, Credit Card, Mobile Payment
3. How to handle reserved parking?
→ Add Reservation class
→ Spot can be reserved for specific time
4. How to handle EV charging spots?
→ Add Charger interface
→ SpotType.EV_CHARGING
5. How to display real-time availability?
→ Observer pattern
→ DisplayBoard updates on park/remove
Design Patterns Used
| Pattern | Where Used |
|---|---|
| Singleton | ParkingLot (one instance) |
| Strategy | PricingStrategy (different rates) |
| Observer | DisplayBoard (updates on changes) |
| Factory | Vehicle creation |
| State | Ticket states (active, completed) |
Scaling Considerations
1. Multiple parking lots:
→ ParkingLotManager manages multiple lots
2. Reservation system:
→ Add booking API
→ Time-slot based reservation
3. Real-time mobile app:
→ WebSocket for live updates
→ Find my car feature
4. Analytics:
→ Track usage patterns
→ Peak hours analysis
5. Integration:
→ Payment gateway
→ SMS notifications
Practice Problems
Design a scalable Parking Lot Design system. Cover high-level architecture, data model, and API design.
Solution
// Complete system design:
// - Functional + Non-functional requirements
// - Capacity estimation
// - Data model (SQL/NoSQL choice)
// - API endpoints
// - Component architecture
// - Scaling strategy
// - Monitoring & reliabilityHow would you scale Parking Lot Design to handle 10x the current load? Identify bottlenecks and solutions.
Solution
// Scaling approach:
// 1. Load balancing
// 2. Database sharding/replication
// 3. Cache layer (Redis)
// 4. CDN for static assets
// 5. Async processing (queues)
// 6. Microservices decompositionAnalyze potential failure modes for Parking Lot Design and design mitigation strategies.
Solution
// Failure mitigation:
// 1. Redundancy (multi-AZ)
// 2. Circuit breakers
// 3. Retry with backoff
// 4. Dead letter queues
// 5. Health checks
// 6. Graceful degradationQuiz
1. What design pattern is used for the ParkingLot class?
2. How does the system determine if a vehicle fits a spot?
3. What pattern is used for pricing?
4. How is the ticket system implemented?
5. How does DisplayBoard get updated?
Flashcards
Question
What design patterns are used in Parking Lot?
Click to reveal answer
Answer
Singleton (ParkingLot), Strategy (pricing), Observer (DisplayBoard), Factory (vehicle), State (ticket).
Question
Vehicle-spot mapping?
Click to reveal answer
Answer
Motorcycle→Compact+, Car→Regular+, Truck→Large only. Hierarchy: Compact < Regular < Large.
Question
Entry flow steps?
Click to reveal answer
Answer
1) Vehicle arrives, 2) Select type, 3) Check availability, 4) Allocate spot, 5) Issue ticket, 6) Open gate.
Question
Exit flow steps?
Click to reveal answer
Answer
1) Scan ticket, 2) Calculate duration, 3) Calculate fee, 4) Process payment, 5) Release spot, 6) Open gate.
Question
Why Singleton for ParkingLot?
Click to reveal answer
Answer
There should be one central system managing all spots across all floors. Singleton ensures single point of control.
Revision Notes
Key Takeaways
- 1.Parking Lot uses Singleton for central control
- 2.Strategy pattern enables flexible pricing per vehicle type
- 3.Observer pattern keeps DisplayBoard updated in real-time
- 4.Vehicle-spot mapping determines which spots fit which vehicles
- 5.Ticket system tracks entry time for fee calculation
Interview Tips
- •Start with requirements and core entities
- •Show class diagram with relationships
- •Explain entry and exit workflows
- •Discuss design patterns used and why
- •Address concurrency for multiple entry/exit panels
Cheat Sheet
Parking Lot Design - Cheat Sheet
Core Entities:
ParkingLot, ParkingFloor, ParkingSpot, Vehicle, Ticket, Payment
Design Patterns:
- Singleton: ParkingLot
- Strategy: PricingStrategy
- Observer: DisplayBoard
- Factory: Vehicle creation
Vehicle-Spot Mapping:
Motorcycle → Compact+
Car → Regular+
Truck → Large only
Workflows:
Entry: Arrive → Select → Check → Allocate → Ticket → Gate
Exit: Scan → Duration → Fee → Pay → Release → Gate
Follow-ups:
- Multiple entry/exit points
- Payment processing
- Reserved parking
- EV charging
- Real-time display