Design a Parking Lot System - Low Level Design
Learn how to design a parking lot management system from scratch using object-oriented principles and design patterns.
Aryansh Kurmi
Software Developer
Design a Parking Lot System - Low Level Design
Designing a parking lot system is one of the most common system design questions asked in technical interviews. It tests your understanding of object-oriented design principles, design patterns, and real-world problem-solving skills.
Problem Statement
Design a parking lot management system that can handle multiple parking spots, different vehicle types, and various operations like parking, unparking, and finding available spots.
Core Requirements
- Vehicle Types: Support different types of vehicles (Car, Motorcycle, Truck)
- Parking Spots: Different spot types for different vehicles
- Operations: Park, unpark, find available spots
- Pricing: Different rates for different vehicle types
- Real-time Status: Track which spots are occupied/available
Class Design
Vehicle Classes
public abstract class Vehicle {
protected String licensePlate;
protected VehicleType type;
protected int spotsNeeded;
public Vehicle(String licensePlate, VehicleType type) {
this.licensePlate = licensePlate;
this.type = type;
}
public abstract boolean canFitInSpot(ParkingSpot spot);
public abstract void print();
}
public class Car extends Vehicle {
public Car(String licensePlate) {
super(licensePlate, VehicleType.CAR);
spotsNeeded = 1;
}
public boolean canFitInSpot(ParkingSpot spot) {
return spot.getSize() == VehicleSize.COMPACT ||
spot.getSize() == VehicleSize.LARGE;
}
public void print() {
System.out.print("Car");
}
}
public class Motorcycle extends Vehicle {
public Motorcycle(String licensePlate) {
super(licensePlate, VehicleType.MOTORCYCLE);
spotsNeeded = 1;
}
public boolean canFitInSpot(ParkingSpot spot) {
return true; // Can fit in any spot
}
public void print() {
System.out.print("Motorcycle");
}
}
public class Truck extends Vehicle {
public Truck(String licensePlate) {
super(licensePlate, VehicleType.TRUCK);
spotsNeeded = 5;
}
public boolean canFitInSpot(ParkingSpot spot) {
return spot.getSize() == VehicleSize.LARGE;
}
public void print() {
System.out.print("Truck");
}
}
Parking Spot Class
public class ParkingSpot {
private Vehicle vehicle;
private VehicleSize size;
private int row;
private int spotNumber;
private Level level;
public ParkingSpot(Level level, int row, int spotNumber, VehicleSize size) {
this.level = level;
this.row = row;
this.spotNumber = spotNumber;
this.size = size;
}
public boolean isAvailable() {
return vehicle == null;
}
public boolean canFitVehicle(Vehicle vehicle) {
return isAvailable() && vehicle.canFitInSpot(this);
}
public boolean park(Vehicle v) {
if (!canFitVehicle(v)) {
return false;
}
vehicle = v;
return true;
}
public void removeVehicle() {
vehicle = null;
}
}
Main ParkingLot Class
public class ParkingLot {
private Level[] levels;
private int numberOfLevels;
public ParkingLot(int numberOfLevels, int spotsPerLevel) {
this.numberLevels = numberOfLevels;
levels = new Level[numberOfLevels];
for (int i = 0; i < numberOfLevels; i++) {
levels[i] = new Level(i, spotsPerLevel);
}
}
public boolean parkVehicle(Vehicle vehicle) {
for (int i = 0; i < levels.length; i++) {
if (levels[i].parkVehicle(vehicle)) {
return true;
}
}
return false;
}
public void removeVehicle(Vehicle vehicle) {
for (int i = 0; i < levels.length; i++) {
levels[i].removeVehicle(vehicle);
}
}
public void print() {
for (int i = 0; i < levels.length; i++) {
System.out.print("Level " + i + ": ");
levels[i].print();
System.out.println("");
}
System.out.println("");
}
}
Key Design Patterns Used
1. Strategy Pattern
Used for different pricing strategies based on vehicle type and time duration.
2. Observer Pattern
For real-time notifications when spots become available or occupied.
3. Factory Pattern
For creating different types of vehicles and parking spots.
Advanced Features
Pricing System
public interface PricingStrategy {
double calculatePrice(Vehicle vehicle, long duration);
}
public class HourlyPricingStrategy implements PricingStrategy {
private Map<VehicleType, Double> hourlyRates;
public double calculatePrice(Vehicle vehicle, long duration) {
double rate = hourlyRates.get(vehicle.getType());
return rate * (duration / 3600000.0); // Convert to hours
}
}
Reservation System
public class Reservation {
private String reservationId;
private Vehicle vehicle;
private ParkingSpot spot;
private Date startTime;
private Date endTime;
private ReservationStatus status;
}
public class ReservationManager {
private Map<String, Reservation> reservations;
public Reservation makeReservation(Vehicle vehicle, Date startTime, Date endTime) {
// Implementation for making reservations
}
}
Testing Strategy
- Unit Tests: Test individual classes and methods
- Integration Tests: Test the interaction between components
- Performance Tests: Test with large numbers of vehicles and spots
- Edge Cases: Test boundary conditions and error scenarios
Scalability Considerations
- Database Integration: Store parking data in a database for persistence
- Caching: Use Redis for frequently accessed data
- Microservices: Split into separate services for different functionalities
- Real-time Updates: Use WebSockets for live updates
Common Interview Questions
- How would you handle concurrent access to parking spots?
- How would you implement a priority system for parking?
- How would you handle payment processing?
- How would you scale this system for multiple parking lots?
Conclusion
This parking lot system design demonstrates the importance of:
- Clear separation of concerns
- Proper use of inheritance and polymorphism
- Design pattern implementation
- Scalability considerations
- Real-world problem-solving approach
The key is to start with the basic requirements and gradually add complexity while maintaining clean, maintainable code.
This post covers the fundamental aspects of designing a parking lot system. In the next post, we'll explore more advanced features like payment processing and real-time monitoring.