Design a Parking Lot System
Learn how to design a parking lot system with object-oriented principles, handling multiple vehicle types, parking spots, and payment processing.
Design a Parking Lot System
Problem Statement
Design a parking lot system that can:
- Handle multiple floors
- Support different vehicle types (Car, Motorcycle, Truck)
- Track available spots
- Calculate parking fees
- Process payments
Requirements
Functional Requirements
- Multiple entry and exit points
- Different parking spot sizes (Compact, Large, Handicapped)
- Real-time availability tracking
- Automated payment system
- Ticket generation and validation
Non-Functional Requirements
- High availability
- Low latency for spot assignment
- Scalable to multiple locations
- Secure payment processing
Class Diagram
ParkingLot
├── floors: List<Floor>
├── entrances: List<Entrance>
├── exits: List<Exit>
└── paymentProcessor: PaymentProcessor
Floor
├── spots: List<ParkingSpot>
└── availableSpots: Map<SpotType, Integer>
ParkingSpot (Abstract)
├── CompactSpot
├── LargeSpot
└── HandicappedSpot
Vehicle (Abstract)
├── Car
├── Motorcycle
└── Truck
Ticket
├── ticketId: String
├── vehicle: Vehicle
├── spot: ParkingSpot
├── entryTime: DateTime
└── exitTime: DateTime
Implementation
Core Classes
public enum VehicleType {
CAR, MOTORCYCLE, TRUCK
}
public enum SpotType {
COMPACT, LARGE, HANDICAPPED
}
public abstract class Vehicle {
private String licensePlate;
private VehicleType type;
public abstract boolean canFitInSpot(ParkingSpot spot);
}
public class Car extends Vehicle {
public Car(String licensePlate) {
super(licensePlate, VehicleType.CAR);
}
@Override
public boolean canFitInSpot(ParkingSpot spot) {
return spot.getType() == SpotType.COMPACT ||
spot.getType() == SpotType.LARGE;
}
}
public abstract class ParkingSpot {
private String spotId;
private SpotType type;
private boolean isAvailable;
private Vehicle currentVehicle;
public boolean park(Vehicle vehicle) {
if (!isAvailable || !vehicle.canFitInSpot(this)) {
return false;
}
this.currentVehicle = vehicle;
this.isAvailable = false;
return true;
}
public void removeVehicle() {
this.currentVehicle = null;
this.isAvailable = true;
}
}
public class ParkingLot {
private static ParkingLot instance;
private List<Floor> floors;
private Map<String, Ticket> activeTickets;
private ParkingLot() {
floors = new ArrayList<>();
activeTickets = new HashMap<>();
}
public static synchronized ParkingLot getInstance() {
if (instance == null) {
instance = new ParkingLot();
}
return instance;
}
public Ticket issueTicket(Vehicle vehicle) {
ParkingSpot spot = findAvailableSpot(vehicle);
if (spot == null) {
throw new NoAvailableSpotException();
}
spot.park(vehicle);
Ticket ticket = new Ticket(vehicle, spot);
activeTickets.put(ticket.getId(), ticket);
return ticket;
}
private ParkingSpot findAvailableSpot(Vehicle vehicle) {
for (Floor floor : floors) {
ParkingSpot spot = floor.findAvailableSpot(vehicle);
if (spot != null) {
return spot;
}
}
return null;
}
public double calculateFee(Ticket ticket) {
long hours = ticket.getDurationInHours();
return hours * 5.0; // $5 per hour
}
}
Design Patterns Used
1. Singleton Pattern
- ParkingLot uses Singleton to ensure single instance
2. Factory Pattern
- VehicleFactory to create different vehicle types
3. Strategy Pattern
- Different pricing strategies (hourly, daily, monthly)
4. Observer Pattern
- Notify when spots become available
Interview Questions
Q1: How would you handle peak hours?
Answer:
- Implement reservation system
- Dynamic pricing during peak hours
- Queue management for waiting vehicles
- Real-time availability updates
Q2: How to scale to multiple locations?
Answer:
- Separate database per location
- Central management system
- Location-based routing
- Distributed caching (Redis)
Q3: How to handle payment failures?
Answer:
- Retry mechanism with exponential backoff
- Multiple payment methods
- Grace period for payment
- Manual payment option at exit
Optimization Strategies
- Caching: Cache available spots count per floor
- Indexing: Index on vehicle license plate and ticket ID
- Load Balancing: Distribute entry/exit processing
- Async Processing: Process payments asynchronously
Conclusion
This parking lot design demonstrates:
- Object-oriented design principles
- Design pattern application
- Scalability considerations
- Real-world problem solving
Key takeaways:
- Use appropriate design patterns
- Consider edge cases
- Plan for scalability
- Handle failures gracefully