|
| 1 | +### Low-Level Design (LLD) for a Parking Lot in Java |
| 2 | + |
| 3 | +When designing a parking lot system, we aim to make it flexible, maintainable, and scalable. The system must handle multiple vehicles and parking spaces, compute parking charges, and ensure proper vehicle entry and exit. We'll break down the design into classes, relationships, and behavior. |
| 4 | + |
| 5 | +### Functional Requirements: |
| 6 | +1. The parking lot should support different types of vehicles (car, bike, truck, etc.). |
| 7 | +2. The system should be able to assign the nearest available parking spot. |
| 8 | +3. The system should compute the parking fee based on the time spent. |
| 9 | +4. The parking lot should have multiple floors and spots. |
| 10 | +5. The system should track vehicles entering and exiting. |
| 11 | + |
| 12 | +### Non-Functional Requirements: |
| 13 | +1. The design should be flexible to add new types of vehicles. |
| 14 | +2. It should be scalable to handle large parking lots with multiple floors. |
| 15 | +3. The design should follow Object-Oriented Principles (OOP) like SOLID. |
| 16 | + |
| 17 | +### Key Classes and Design |
| 18 | + |
| 19 | +#### 1. **ParkingLot** |
| 20 | + - The `ParkingLot` class represents the entire parking structure and contains the list of floors. |
| 21 | + - It tracks the total number of parking spaces and manages vehicle entry/exit. |
| 22 | + |
| 23 | +```java |
| 24 | +public class ParkingLot { |
| 25 | + private List<ParkingFloor> floors; |
| 26 | + private String parkingLotName; |
| 27 | + |
| 28 | + public ParkingLot(String parkingLotName, int numberOfFloors) { |
| 29 | + this.parkingLotName = parkingLotName; |
| 30 | + this.floors = new ArrayList<>(); |
| 31 | + for (int i = 1; i <= numberOfFloors; i++) { |
| 32 | + floors.add(new ParkingFloor(i)); |
| 33 | + } |
| 34 | + } |
| 35 | + |
| 36 | + public boolean parkVehicle(Vehicle vehicle) { |
| 37 | + for (ParkingFloor floor : floors) { |
| 38 | + if (floor.parkVehicle(vehicle)) { |
| 39 | + return true; |
| 40 | + } |
| 41 | + } |
| 42 | + return false; // Parking is full |
| 43 | + } |
| 44 | + |
| 45 | + public boolean unParkVehicle(Vehicle vehicle) { |
| 46 | + for (ParkingFloor floor : floors) { |
| 47 | + if (floor.unParkVehicle(vehicle)) { |
| 48 | + return true; |
| 49 | + } |
| 50 | + } |
| 51 | + return false; // Vehicle not found |
| 52 | + } |
| 53 | +} |
| 54 | +``` |
| 55 | + |
| 56 | +#### 2. **ParkingFloor** |
| 57 | + - Represents a single floor within the parking lot. Each floor has multiple parking spots. |
| 58 | + |
| 59 | +```java |
| 60 | +public class ParkingFloor { |
| 61 | + private int floorNumber; |
| 62 | + private List<ParkingSpot> spots; |
| 63 | + |
| 64 | + public ParkingFloor(int floorNumber) { |
| 65 | + this.floorNumber = floorNumber; |
| 66 | + this.spots = new ArrayList<>(); |
| 67 | + // Initialize parking spots for the floor |
| 68 | + initializeSpots(); |
| 69 | + } |
| 70 | + |
| 71 | + private void initializeSpots() { |
| 72 | + for (int i = 1; i <= 20; i++) { // 20 spots per floor |
| 73 | + spots.add(new ParkingSpot(i, SpotType.CAR)); // Default to car spots |
| 74 | + } |
| 75 | + } |
| 76 | + |
| 77 | + public boolean parkVehicle(Vehicle vehicle) { |
| 78 | + for (ParkingSpot spot : spots) { |
| 79 | + if (spot.isAvailable() && spot.canFitVehicle(vehicle)) { |
| 80 | + spot.assignVehicle(vehicle); |
| 81 | + return true; |
| 82 | + } |
| 83 | + } |
| 84 | + return false; // No available spot on this floor |
| 85 | + } |
| 86 | + |
| 87 | + public boolean unParkVehicle(Vehicle vehicle) { |
| 88 | + for (ParkingSpot spot : spots) { |
| 89 | + if (!spot.isAvailable() && spot.getVehicle().equals(vehicle)) { |
| 90 | + spot.removeVehicle(); |
| 91 | + return true; |
| 92 | + } |
| 93 | + } |
| 94 | + return false; // Vehicle not found on this floor |
| 95 | + } |
| 96 | +} |
| 97 | +``` |
| 98 | + |
| 99 | +#### 3. **ParkingSpot** |
| 100 | + - Each parking spot holds a vehicle and knows whether it is occupied or not. |
| 101 | + |
| 102 | +```java |
| 103 | +public class ParkingSpot { |
| 104 | + private int spotNumber; |
| 105 | + private SpotType type; |
| 106 | + private Vehicle vehicle; |
| 107 | + |
| 108 | + public ParkingSpot(int spotNumber, SpotType type) { |
| 109 | + this.spotNumber = spotNumber; |
| 110 | + this.type = type; |
| 111 | + this.vehicle = null; |
| 112 | + } |
| 113 | + |
| 114 | + public boolean isAvailable() { |
| 115 | + return vehicle == null; |
| 116 | + } |
| 117 | + |
| 118 | + public boolean canFitVehicle(Vehicle vehicle) { |
| 119 | + return this.type.canFitVehicle(vehicle); |
| 120 | + } |
| 121 | + |
| 122 | + public void assignVehicle(Vehicle vehicle) { |
| 123 | + this.vehicle = vehicle; |
| 124 | + } |
| 125 | + |
| 126 | + public void removeVehicle() { |
| 127 | + this.vehicle = null; |
| 128 | + } |
| 129 | + |
| 130 | + public Vehicle getVehicle() { |
| 131 | + return this.vehicle; |
| 132 | + } |
| 133 | +} |
| 134 | +``` |
| 135 | + |
| 136 | +#### 4. **Vehicle** |
| 137 | + - Base class for different types of vehicles. |
| 138 | + |
| 139 | +```java |
| 140 | +public abstract class Vehicle { |
| 141 | + private String licensePlate; |
| 142 | + private VehicleSize size; |
| 143 | + |
| 144 | + public Vehicle(String licensePlate, VehicleSize size) { |
| 145 | + this.licensePlate = licensePlate; |
| 146 | + this.size = size; |
| 147 | + } |
| 148 | + |
| 149 | + public String getLicensePlate() { |
| 150 | + return licensePlate; |
| 151 | + } |
| 152 | + |
| 153 | + public VehicleSize getSize() { |
| 154 | + return size; |
| 155 | + } |
| 156 | +} |
| 157 | + |
| 158 | +public class Car extends Vehicle { |
| 159 | + public Car(String licensePlate) { |
| 160 | + super(licensePlate, VehicleSize.COMPACT); |
| 161 | + } |
| 162 | +} |
| 163 | + |
| 164 | +public class Bike extends Vehicle { |
| 165 | + public Bike(String licensePlate) { |
| 166 | + super(licensePlate, VehicleSize.SMALL); |
| 167 | + } |
| 168 | +} |
| 169 | + |
| 170 | +public class Truck extends Vehicle { |
| 171 | + public Truck(String licensePlate) { |
| 172 | + super(licensePlate, VehicleSize.LARGE); |
| 173 | + } |
| 174 | +} |
| 175 | +``` |
| 176 | + |
| 177 | +#### 5. **SpotType** and **VehicleSize** |
| 178 | + - Enumerations to represent the type of spot and vehicle size. |
| 179 | + |
| 180 | +```java |
| 181 | +public enum SpotType { |
| 182 | + CAR, BIKE, TRUCK; |
| 183 | + |
| 184 | + public boolean canFitVehicle(Vehicle vehicle) { |
| 185 | + switch (this) { |
| 186 | + case CAR: |
| 187 | + return vehicle.getSize() == VehicleSize.COMPACT; |
| 188 | + case BIKE: |
| 189 | + return vehicle.getSize() == VehicleSize.SMALL; |
| 190 | + case TRUCK: |
| 191 | + return vehicle.getSize() == VehicleSize.LARGE; |
| 192 | + default: |
| 193 | + return false; |
| 194 | + } |
| 195 | + } |
| 196 | +} |
| 197 | + |
| 198 | +public enum VehicleSize { |
| 199 | + SMALL, COMPACT, LARGE; |
| 200 | +} |
| 201 | +``` |
| 202 | + |
| 203 | +#### 6. **ParkingTicket** |
| 204 | + - Each vehicle is assigned a parking ticket upon entry. This ticket tracks entry time and is used to compute the total parking duration. |
| 205 | + |
| 206 | +```java |
| 207 | +import java.time.LocalDateTime; |
| 208 | + |
| 209 | +public class ParkingTicket { |
| 210 | + private String ticketId; |
| 211 | + private LocalDateTime entryTime; |
| 212 | + private LocalDateTime exitTime; |
| 213 | + private Vehicle vehicle; |
| 214 | + private ParkingSpot spot; |
| 215 | + |
| 216 | + public ParkingTicket(Vehicle vehicle, ParkingSpot spot) { |
| 217 | + this.ticketId = generateTicketId(); |
| 218 | + this.vehicle = vehicle; |
| 219 | + this.spot = spot; |
| 220 | + this.entryTime = LocalDateTime.now(); |
| 221 | + } |
| 222 | + |
| 223 | + public void markExit() { |
| 224 | + this.exitTime = LocalDateTime.now(); |
| 225 | + } |
| 226 | + |
| 227 | + public long calculateDuration() { |
| 228 | + if (exitTime == null) { |
| 229 | + throw new IllegalStateException("Vehicle has not exited yet."); |
| 230 | + } |
| 231 | + return java.time.Duration.between(entryTime, exitTime).toMinutes(); |
| 232 | + } |
| 233 | + |
| 234 | + private String generateTicketId() { |
| 235 | + return "TICKET-" + System.currentTimeMillis(); |
| 236 | + } |
| 237 | + |
| 238 | + public Vehicle getVehicle() { |
| 239 | + return vehicle; |
| 240 | + } |
| 241 | +} |
| 242 | +``` |
| 243 | + |
| 244 | +#### 7. **ParkingChargeCalculator** |
| 245 | + - This class computes the total fee based on the duration and the type of vehicle. |
| 246 | + |
| 247 | +```java |
| 248 | +public class ParkingChargeCalculator { |
| 249 | + private static final int BASE_RATE = 10; // Base rate per hour |
| 250 | + |
| 251 | + public static int calculateFee(ParkingTicket ticket) { |
| 252 | + long durationInMinutes = ticket.calculateDuration(); |
| 253 | + int hours = (int) Math.ceil(durationInMinutes / 60.0); |
| 254 | + |
| 255 | + Vehicle vehicle = ticket.getVehicle(); |
| 256 | + int rate = BASE_RATE; |
| 257 | + |
| 258 | + if (vehicle instanceof Truck) { |
| 259 | + rate *= 3; // Trucks have a higher rate |
| 260 | + } else if (vehicle instanceof Bike) { |
| 261 | + rate /= 2; // Bikes have a lower rate |
| 262 | + } |
| 263 | + return rate * hours; |
| 264 | + } |
| 265 | +} |
| 266 | +``` |
| 267 | + |
| 268 | +### Summary of Classes: |
| 269 | +- `ParkingLot`: Manages parking floors and entry/exit of vehicles. |
| 270 | +- `ParkingFloor`: Manages parking spots on a particular floor. |
| 271 | +- `ParkingSpot`: Holds information about each individual parking spot. |
| 272 | +- `Vehicle`: Base class for all types of vehicles (Bike, Car, Truck). |
| 273 | +- `ParkingTicket`: Tracks the entry, exit, and duration for each vehicle. |
| 274 | +- `ParkingChargeCalculator`: Computes the fee based on time and vehicle type. |
| 275 | +- `SpotType` & `VehicleSize`: Enum types to represent spot and vehicle sizes. |
| 276 | + |
| 277 | +### Key Design Principles: |
| 278 | +- **Single Responsibility Principle**: Each class has a single responsibility, like `ParkingLot` manages floors, and `ParkingSpot` manages vehicle allocation. |
| 279 | +- **Open/Closed Principle**: It’s easy to extend the system to add more vehicle types without modifying existing code. |
| 280 | +- **Encapsulation**: Each class hides its internal workings and provides public methods to interact with other classes. |
| 281 | + |
| 282 | +This design can be scaled up by adding more features like payment systems, reserved parking, and integration with IoT systems. |
0 commit comments