Design and implement an object-oriented parking facility management system that can handle multiple types of vehicles across different parking levels. Your system should efficiently allocate parking spaces, track availability, and manage vehicle entry and exit operations.
This is a system design problem focused on demonstrating your ability to create clean, extensible object-oriented code with proper abstractions and relationships between entities.
Your parking management system must support the following functionality:
Your implementation should include these key classes:
` Facility Setup:
Operations:
Hint 1: Class Relationships Think about the hierarchy of your system from top to bottom:
- The ParkingLot contains multiple ParkingLevels
- Each ParkingLevel contains multiple ParkingSpots
- Each ParkingSpot can be occupied by at most one Vehicle
Use composition to build these relationships. The ParkingLot should be the main interface that clients interact with, delegating work to lower-level components.
Hint 2: Spot Assignment Strategy When assigning a spot to a vehicle:
- Determine the minimum spot type required for the vehicle size
- Iterate through levels to find an available spot of appropriate type
- Mark the spot as occupied and associate it with the vehicle
- Consider storing a mapping of vehicles to their assigned spots for quick lookup during departure
For space efficiency, prefer assigning the smallest appropriate spot type (e.g., give a motorcycle a compact spot if available before using a regular spot).
Hint 3: State Management Each ParkingSpot needs to track:
- Its type (compact, regular, large)
- Whether it's currently occupied
- Which vehicle is parked there (if any)
Each ParkingLevel should maintain:
- A collection of all its spots
- Count of available spots by type for quick availability checks
The ParkingLot should coordinate operations across all levels.
Full Solution `` Solution Explanation:
This implementation follows object-oriented design principles with clear separation of concerns:
Enumerations:
VehicleSizeandParkingSpotTypeprovide type-safe categorizationVehicle Class: Simple data container that tracks vehicle information and its current parking spot
ParkingSpot Class:
- Manages occupancy state
- Implements fitting logic (motorcycles fit anywhere, cars need regular/large, buses need large)
- Handles parking and removal operations
ParkingLevel Class:
- Aggregates multiple spots
- Provides search functionality to find available spots
- Tracks availability metrics by spot type
ParkingLot Class:
- The main facade/coordinator
- Manages multiple levels
- Maintains a vehicle registry for O(1) lookup
- Delegates spot finding to levels
Time Complexity:
- Parking a vehicle: O(n) where n is the total number of spots (worst case: iterate all levels and spots)
- Removing a vehicle: O(1) with the license plate map
- Checking availability: O(m) where m is the number of levels
Space Complexity: O(s + v) where s is the number of spots and v is the number of parked vehicles
The design is extensible—you can easily add new vehicle types, spot types, or pricing logic without modifying existing code. This demonstrates the Open-Closed Principle and proper encapsulation.
from enum import Enum
from datetime import datetime
from typing import Optional, List
class VehicleSize(Enum):
"""Enumeration of vehicle size categories"""
MOTORCYCLE = 1
CAR = 2
BUS = 3
class ParkingSpotType(Enum):
"""Enumeration of parking spot size categories"""
COMPACT = 1
REGULAR = 2
LARGE = 3
class Vehicle:
"""Represents a vehicle that can be parked"""
def __init__(self, license_plate: str, size: VehicleSize):
self.license_plate = license_plate
self.size = size
self.parked_at = None # Reference to assigned ParkingSpot
def __str__(self):
return f"Vehicle({self.license_plate}, {self.size.name})"
class ParkingSpot:
"""Represents an individual parking space"""
def __init__(self, spot_id: int, spot_type: ParkingSpotType, level: int):
self.spot_id = spot_id
self.spot_type = spot_type
self.level = level
self.vehicle: Optional[Vehicle] = None
def is_available(self) -> bool:
"""Check if this spot is currently unoccupied"""
return self.vehicle is None
def can_fit_vehicle(self, vehicle: Vehicle) -> bool:
"""Determine if this spot can accommodate the given vehicle"""
if not self.is_available():
return False
# Motorcycles can fit in any spot
if vehicle.size == VehicleSize.MOTORCYCLE:
return True
# Cars need at least regular spots
elif vehicle.size == VehicleSize.CAR:
return self.spot_type in [ParkingSpotType.REGULAR, ParkingSpotType.LARGE]
# Buses need large spots
elif vehicle.size == VehicleSize.BUS:
return self.spot_type == ParkingSpotType.LARGE
return False
def park_vehicle(self, vehicle: Vehicle) -> bool:
"""Attempt to park a vehicle in this spot"""
if self.can_fit_vehicle(vehicle):
self.vehicle = vehicle
vehicle.parked_at = self
return True
return False
def remove_vehicle(self) -> Optional[Vehicle]:
"""Remove and return the parked vehicle"""
vehicle = self.vehicle
if vehicle:
vehicle.parked_at = None
self.vehicle = None
return vehicle
def __str__(self):
status = "Occupied" if self.vehicle else "Available"
return f"Spot {self.spot_id} (Level {self.level}, {self.spot_type.name}): {status}"
class ParkingLevel:
"""Represents a floor/level containing multiple parking spots"""
def __init__(self, level_number: int):
self.level_number = level_number
self.spots: List[ParkingSpot] = []
def add_spot(self, spot_type: ParkingSpotType):
"""Add a new parking spot to this level"""
spot_id = len(self.spots)
spot = ParkingSpot(spot_id, spot_type, self.level_number)
self.spots.append(spot)
def find_available_spot(self, vehicle: Vehicle) -> Optional[ParkingSpot]:
"""Find the first available spot that can fit the vehicle"""
for spot in self.spots:
if spot.can_fit_vehicle(vehicle):
return spot
return None
def get_available_spots_count(self) -> int:
"""Count total available spots on this level"""
return sum(1 for spot in self.spots if spot.is_available())
def get_available_spots_by_type(self, spot_type: ParkingSpotType) -> int:
"""Count available spots of a specific type"""
return sum(1 for spot in self.spots
if spot.is_available() and spot.spot_type == spot_type)
class ParkingLot:
"""Main parking facility management system"""
def __init__(self, name: str):
self.name = name
self.levels: List[ParkingLevel] = []
self.vehicle_map = {} # Maps license_plate to Vehicle for quick lookup
def add_level(self, level: ParkingLevel):
"""Add a parking level to the facility"""
self.levels.append(level)
def park_vehicle(self, vehicle: Vehicle) -> bool:
"""
Attempt to park a vehicle in the first available appropriate spot.
Returns True if successful, False otherwise.
"""
if vehicle.license_plate in self.vehicle_map:
print(f"Vehicle {vehicle.license_plate} is already parked")
return False
# Try to find a spot across all levels
for level in self.levels:
spot = level.find_available_spot(vehicle)
if spot:
if spot.park_vehicle(vehicle):
self.vehicle_map[vehicle.license_plate] = vehicle
print(f"Parked {vehicle} at {spot}")
return True
print(f"No available spot for {vehicle}")
return False
def remove_vehicle(self, license_plate: str) -> bool:
"""
Remove a vehicle from the parking lot.
Returns True if successful, False if vehicle not found.
"""
if license_plate not in self.vehicle_map:
print(f"Vehicle {license_plate} not found in parking lot")
return False
vehicle = self.vehicle_map[license_plate]
if vehicle.parked_at:
vehicle.parked_at.remove_vehicle()
del self.vehicle_map[license_plate]
print(f"Removed vehicle {license_plate}")
return True
return False
def get_available_spots_count(self) -> int:
"""Get total number of available spots in the entire facility"""
return sum(level.get_available_spots_count() for level in self.levels)
def display_status(self):
"""Display current status of the parking facility"""
print(f"\n=== {self.name} Status ===")
print(f"Total vehicles parked: {len(self.vehicle_map)}")
print(f"Available spots: {self.get_available_spots_count()}")
for level in self.levels:
print(f"\nLevel {level.level_number}:")
print(f" Available spots: {level.get_available_spots_count()}")
print(f" Compact: {level.get_available_spots_by_type(ParkingSpotType.COMPACT)}")
print(f" Regular: {level.get_available_spots_by_type(ParkingSpotType.REGULAR)}")
print(f" Large: {level.get_available_spots_by_type(ParkingSpotType.LARGE)}")
# Example usage demonstrating the system
def demo_parking_system():
# Create parking lot
parking_lot = ParkingLot("City Center Parking")
# Create Level 1 with mixed spot types
level1 = ParkingLevel(1)
for _ in range(10):
level1.add_spot(ParkingSpotType.COMPACT)
for _ in range(20):
level1.add_spot(ParkingSpotType.REGULAR)
parking_lot.add_level(level1)
# Create Level 2 with regular and large spots
level2 = ParkingLevel(2)
for _ in range(15):
level2.add_spot(ParkingSpotType.REGULAR)
for _ in range(5):
level2.add_spot(ParkingSpotType.LARGE)
parking_lot.add_level(level2)
# Create Level 3 with mostly compact spots
level3 = ParkingLevel(3)
for _ in range(30):
level3.add_spot(ParkingSpotType.COMPACT)
parking_lot.add_level(level3)
# Display initial status
parking_lot.display_status()
# Park some vehicles
motorcycle1 = Vehicle("MOTO-001", VehicleSize.MOTORCYCLE)
car1 = Vehicle("CAR-001", VehicleSize.CAR)
bus1 = Vehicle("BUS-001", VehicleSize.BUS)
car2 = Vehicle("CAR-002", VehicleSize.CAR)
print("\n--- Parking Vehicles ---")
parking_lot.park_vehicle(motorcycle1)
parking_lot.park_vehicle(car1)
parking_lot.park_vehicle(bus1)
parking_lot.park_vehicle(car2)
# Display status after parking
parking_lot.display_status()
# Remove a vehicle
print("\n--- Removing Vehicle ---")
parking_lot.remove_vehicle("CAR-001")
# Display final status
parking_lot.display_status()
if __name__ == "__main__":
demo_parking_system()