Parking Lot Project Low Level Design
π Parking Lot Project — Interview Summary
π― Purpose
This project simulates a Parking Lot Management System using Spring Boot + Core Java OOP Design Patterns.
It allows:
-
Adding parking floors and parking spots
-
Parking and unparking vehicles
-
Generating parking tickets
-
Calculating parking fees using pricing strategies
-
Making payments using different payment strategies
⚙️ High-Level Architecture
π¦ 1. Entity Layer (entity package)
Represents the core data objects:
-
Vehicle
-
Contains vehicle number and type (
CAR,BIKE,TRUCK)
-
-
ParkingSpot
-
Has
id,allowedType, andoccupiedstatus (AtomicBoolean for thread-safety)
-
-
ParkingFloor
-
Has
idand multipleParkingSpotobjects in aConcurrentHashMap
-
-
Ticket
-
Contains
ticketId,entryTime,exitTime,vehicle,floorId,spotId, andpaymentStatus
-
⚙️ 2. Enum Layer (enumpack package)
Defines system constants:
-
VehicleType →
CAR,BIKE,TRUCK -
PaymentMode →
CASH,UPI,CARD -
PricingStrategyType →
TIME_BASED,FLAT_RATE
⚙️ 3. Strategy Layer (strategy package)
Implements the Strategy Design Pattern.
-
Pricing Strategy (
strategy.pricing)-
Interface:
PricingStrategy -
Implementations:
TimeBasedPricing,FlatRatePricing -
Chosen via
PricingStrategyFactory
-
-
Payment Strategy (
strategy.payment)-
Interface:
PaymentStrategy -
Implementations:
CashPayment,UpiPayment,CardPayment -
Chosen via
PaymentStrategyFactory
-
-
PaymentProcessor
-
A utility class that executes the payment using a selected
PaymentStrategy.
-
✅ This pattern lets you switch or extend new pricing or payment logic without changing main code.
⚙️ 4. Factory Layer (factory package)
-
VehicleFactory → creates
Vehicleobjects based on type -
PricingStrategyFactory → returns correct
PricingStrategyinstance -
PaymentStrategyFactory → returns correct
PaymentStrategyinstance
✅ This uses Factory Design Pattern to centralize object creation.
⚙️ 5. Service Layer (services package)
-
ParkingLot (Singleton)
-
Central brain of the system
-
Maintains:
-
All
ParkingFloorobjects -
All active
Ticketobjects
-
-
Responsibilities:
-
addFloor() -
parkVehicle()→ finds available spot and generates ticket -
unparkVehicle()→ calculates fee, takes payment, and vacates spot -
printStatus()→ shows all floors and their spot statuses
-
-
✅ This uses the Singleton Design Pattern so only one ParkingLot object exists globally.
⚙️ 6. Main Runner (Spring Boot)
-
ParkingALotApplication
-
Implements
CommandLineRunner -
On application startup, it:
-
Creates a floor with multiple spots
-
Creates vehicles and parks them
-
Prints status
-
Unparks vehicles and does payment
-
Prints final status
π Logical Flow (Runtime Flow)
Here’s what happens when the app runs:
Application Start
|
v
Create ParkingLot (Singleton)
|
v
Add ParkingFloor -> Add ParkingSpots
|
v
parkVehicle(vehicle)
- findAvailableSpot() on each floor
- if found: tryOccupy() spot atomically
- create Ticket (ticketId, floorId, spotId, entryTime)
- store ticket in activeTickets
|
v
unparkVehicle(ticketId)
- get ticket from activeTickets
- calculate fee using pricingStrategy
- get paymentStrategy using PaymentStrategyFactory
- process payment
- if payment success: vacate spot, remove ticket
π Design Patterns Used
| Pattern | Used In | Purpose |
|---|---|---|
| Singleton | ParkingLot | Only one global ParkingLot manager |
| Factory | VehicleFactory, PaymentStrategyFactory, PricingStrategyFactory | Centralized object creation |
| Strategy | Pricing & Payment modules | Easily switch algorithms at runtime |
| Builder (optional) | Ticket (if Lombok used) | Object creation (replaced with setters now) |
| CommandLineRunner | Main class | Bootstrapping logic on app start |
✅ Interview Selling Points
-
Thread-safe parking spots using
AtomicBoolean -
Scalable architecture — easy to add new vehicle types, pricing models, payment types
-
Clean separation of responsibilities (SRP - Single Responsibility Principle)
-
Extensible design using Strategy + Factory patterns
-
Demonstrates real-world system design principles
1. Entry Point – Vehicle Arrives
-
A vehicle comes at the entry gate.
-
System needs to:
-
Identify vehicle type (Car, Bike, Truck).
-
Find a free spot suitable for that type.
-
π Handled by: ParkingLot.parkVehicle(vehicle, entryTime)
2. Finding a Spot
-
System iterates over all floors (
ParkingFloor). -
Each floor checks its
ParkingSpots. -
Conditions to allocate:
-
Spot supports same vehicle type.
-
Spot is not occupied.
-
-
If free →
tryOccupy()marks it atomically occupied (thread-safe).
π Outcome: A unique spot is reserved.
3. Issuing a Ticket
-
Once spot is found → create a
Ticket. -
Ticket contains:
-
Ticket ID (UUID).
-
Vehicle details.
-
Floor ID + Spot ID.
-
Entry time.
-
-
Ticket stored in
activeTicketsmap.
π Outcome: Driver gets a proof of parking.
4. Parking Status During Stay
-
Admin/system can check
printStatus(). -
Shows:
-
Each floor.
-
Each spot → Occupied or Free.
-
-
Helps in monitoring.
5. Exit – Vehicle Leaves
-
Driver provides Ticket ID at exit.
-
System fetches ticket from
activeTickets. -
If ticket invalid → reject.
π Handled by: ParkingLot.unparkVehicle(ticketId, exitTime, paymentMode)
6. Fee Calculation
-
System calculates charges using
PricingStrategy. -
Example strategies:
-
Time-based → Normal vs Peak hours.
-
Event-based → Fixed per hour.
-
π Flexible, because it uses Strategy Pattern.
7. Payment Processing
-
Based on driver’s choice → UPI, Cash, Card.
-
System picks correct
PaymentStrategyvia factory. -
Processes payment using
PaymentProcessor. -
If payment fails → don’t allow exit.
8. Freeing the Spot
-
If payment success:
-
Locate the spot (from ticket).
-
Call
vacate()→ mark it free. -
Remove ticket from
activeTickets.
-
π Outcome: Vehicle exits, spot becomes available.
9. End State
-
Vehicle is out.
-
Ticket no longer active.
-
Parking space ready for next vehicle.
π Complete Flow Recap
-
Vehicle enters →
parkVehicle. -
Find free spot → allocate & mark occupied.
-
Issue ticket → store in activeTickets.
-
Vehicle stays → status can be printed.
-
Vehicle exits →
unparkVehicle. -
Fetch ticket → calculate fee.
-
Process payment (UPI/Cash/Card).
-
Free the spot → remove ticket.
-
System updated, ready for next cycle.
π Parking Lot – UML / Architecture Overview
1. Core Entities (Domain Layer)
Vehicle
-
Variables:
id,type (VehicleType) -
Methods: getters
ParkingSpot
-
Variables:
id,allowedType,occupied (AtomicBoolean) -
Methods:
-
tryOccupy()– atomically mark spot as taken -
vacate()– free spot -
isOccupied()– check status
-
ParkingFloor
-
Variables:
id,spots (Map<spotId, ParkingSpot>) -
Methods:
-
addSpot(ParkingSpot) -
findAvailableSpot(VehicleType)→Optional<ParkingSpot> -
vacateSpot(String spotId)
-
Ticket
-
Variables:
ticketId,vehicle,entryTime,floorId,spotId -
Methods: getters/setters
2. Services (Business Logic Layer)
ParkingLot (Singleton)
-
Variables:
-
floors (Map<floorId, ParkingFloor>) -
activeTickets (Map<ticketId, Ticket>) -
pricingStrategy (PricingStrategy)
-
-
Methods:
-
addFloor(ParkingFloor) -
parkVehicle(Vehicle, entryTime)→Ticket -
unparkVehicle(ticketId, exitTime, PaymentMode) -
printStatus()
-
3. Strategies (Behavioral Layer – Strategy Pattern)
PricingStrategy (interface)
-
calculateFee(VehicleType, entryTime, exitTime)
Implementations:
-
TimeBasedPricing – fee = hours * rate
-
FlatPricing – fixed fee
PaymentStrategy (interface)
-
pay(Ticket, fee)
Implementations:
-
CashPayment
-
CardPayment
-
UPIPayment
4. Factories (Creational Layer – Factory Pattern)
PricingStrategyFactory
-
get(PricingStrategyType)→ returns correct strategy
PaymentStrategyFactory
-
get(PaymentMode)→ returns correct payment strategy
5. Supporting Enums
-
VehicleType →
CAR, BIKE, TRUCK -
GateType →
ENTRY, EXIT -
PricingStrategyType →
TIME_BASED, FLAT -
PaymentMode →
CASH, CARD, UPI
π¦ High-Level Flow (Revision)
-
Vehicle arrives at EntryGate
→ParkingLot.parkVehicle()
→ParkingFloor.findAvailableSpot()
→ParkingSpot.tryOccupy()
→Ticket generated -
Vehicle exits via ExitGate
→ParkingLot.unparkVehicle()
→PricingStrategy.calculateFee()
→PaymentStrategy.pay()
→Spot.vacate()
→Ticket removed from active list
step-by-step flow
Entry flow (park)
-
Vehicle arrives at EntryGate → Gate collects vehicle info (license, type).
-
EntryGate calls
ParkingLot.parkVehicle(vehicle, entryTime)(delegation). -
ParkingLot:
-
Iterates floors:
floor.findAvailableSpot(vehicle.getType())-
ParkingFloor.findAvailableSpot(...)iterates spots and callsspot.tryOccupy()(atomic).
-
-
If a spot is found: ParkingLot creates Ticket (single responsibility):
-
ticketId,entryTime,vehicle,floorId,spotId,paymentStatus = PENDING
-
-
Store ticket in
activeTicketsmap (ticketId → Ticket). -
Return
Ticketto EntryGate (so gate can open and hand ticket to driver).
-
-
EntryGate shows ticket and opens gate.
Notes: tryOccupy() prevents race conditions. Only ParkingLot writes to activeTickets.
for (ParkingFloor floor : floors.values()) {
Optional<ParkingSpot> spotOpt = floor.findAvailableSpot(vehicle.getType());
if (spotOpt.isPresent()) {
ParkingSpot spot = spotOpt.get();
String ticketId = UUID.randomUUID().toString();
// ✅ Use setters instead of builder
Ticket ticket = new Ticket();
ticket.setTicketId(ticketId);
ticket.setVehicle(vehicle);
ticket.setEntryTime(entryTime);
ticket.setFloorId(floor.getId());
ticket.setSpotId(spot.getId());
activeTickets.put(ticketId, ticket);
System.out.println("Vehicle parked. Ticket: " + ticketId);
return ticket;
}
}
System.out.println("No spot available for vehicle type: " + vehicle.getType());
return null;
}
for (ParkingSpot spot : spots.values()) {
if (spot.getAllowedType() == vehicleType && spot.tryOccupy()) {
return Optional.of(spot);
}
}
return Optional.empty();
}
return allowedType;
}
return occupied.compareAndSet(false, true);
}
import enumpack.VehicleType;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import services.ParkingLot;
import entity.ParkingFloor;
import entity.ParkingSpot;
import entity.Vehicle;
import factory.VehicleFactory;
import enumpack.PaymentMode;
import java.time.LocalDateTime;
@SpringBootApplication
public class ParkingALotApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(ParkingALotApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
// Get singleton ParkingLot instance
ParkingLot parkingLot = ParkingLot.getInstance();
// Create and add a floor with spots
ParkingFloor floor1 = new ParkingFloor("F1");
floor1.addSpot(new ParkingSpot("S1", VehicleType.CAR));
floor1.addSpot(new ParkingSpot("S2", VehicleType.BIKE));
floor1.addSpot(new ParkingSpot("S3", VehicleType.TRUCK));
parkingLot.addFloor(floor1);
// Park a Car
Vehicle car = VehicleFactory.create("MH12AB1234", VehicleType.CAR);
LocalDateTime entryTime = LocalDateTime.now().minusHours(2); // parked 2 hours ago
var carTicket = parkingLot.parkVehicle(car, entryTime);
// Park a Bike
Vehicle bike = VehicleFactory.create("DL10XY9999", VehicleType.BIKE);
LocalDateTime bikeEntry = LocalDateTime.now().minusHours(1); // parked 1 hour ago
var bikeTicket = parkingLot.parkVehicle(bike, bikeEntry);
// Print parking lot status
System.out.println("\n--- Parking Lot Status ---");
parkingLot.printStatus();
// Unpark vehicles and pay
System.out.println("\n--- Unparking Vehicles ---");
if (carTicket != null) {
parkingLot.unparkVehicle(carTicket.getTicketId(), LocalDateTime.now(), PaymentMode.UPI);
}
if (bikeTicket != null) {
parkingLot.unparkVehicle(bikeTicket.getTicketId(), LocalDateTime.now(), PaymentMode.CASH);
}
// Print status after unparking
System.out.println("\n--- Parking Lot Status After Exit ---");
parkingLot.printStatus();
}
}
private final Map<String, ParkingSpot> spots = new ConcurrentHashMap<>();
Key → Value
-
Key:
spotId(String) → unique identifier of the parking spot, e.g.,"S1","S2","B1". -
Value:
ParkingSpot→ the actual spot object which holds: -
id -
allowedType(VehicleType: CAR, BIKE, TRUCK) -
occupied(AtomicBoolean)
Why Map?
-
Fast lookup by spot ID (
spots.get(spotId)when vacating). -
Thread-safe iteration + atomic operations (
ConcurrentHashMap+tryOccupy()).
floors Map
-
Key:
floorId(String) → e.g.,"F1","F2" -
Value:
ParkingFloorobject
Example
Complete Code Link --shivamofficial/Parkinglot-LLD
...
Comments
Post a Comment