Design A Parking Lot System

Shohanur RahmanShohanur Rahman
4 min read

πŸ“š High-Level Overview

A Parking Lot System is a software solution to manage vehicle parking in an organized way. It should handle:

  • Vehicle entry and exit.

  • Tracking available and occupied spots.

  • Calculating parking fees.

  • Supporting different vehicle types (e.g., Car, Bike, Truck).

  • Multiple parking floors (if applicable).

We will design the system considering scalability, maintainability, and using Object-Oriented Principles and appropriate Design Patterns.


πŸ› οΈ Key Requirements

Functional Requirements

  • Allow vehicles to enter and exit the parking lot.

  • Different types of vehicles may occupy different parking spots.

  • Maintain real-time status of parking spot availability.

  • Calculate parking fees based on time and vehicle type.

Non-Functional Requirements

  • Scalable: Should support multiple parking floors.

  • Efficient: Quick lookups for spot availability.

  • Maintainable: Clear separation of concerns.


🧠 Key Design Components

  1. Parking Lot: Manages all parking floors and spots.

  2. Parking Floor: Represents each floor and its spots.

  3. Parking Spot: Represents an individual parking spot.

  4. Vehicle: Represents vehicles (Car, Bike, Truck, etc.).

  5. Ticket: Issued when a vehicle enters the parking lot.

  6. Payment System: Calculates and processes payments.


πŸ“ Design Patterns Used

  1. Factory Pattern: To create vehicle and spot objects dynamically.

  2. Strategy Pattern: To calculate parking fees for different vehicle types.

  3. Singleton Pattern: To ensure only one instance of the ParkingLot class exists.


πŸ“ Class Diagram

diffCopy codeParkingLot
- List<ParkingFloor> floors
- Map<String, ParkingSpot> occupiedSpots
+ parkVehicle(vehicle: Vehicle): Ticket
+ leaveVehicle(ticket: Ticket): double

ParkingFloor
- List<ParkingSpot> spots
+ getAvailableSpot(vehicleType: VehicleType): ParkingSpot

ParkingSpot
- String id
- VehicleType type
- boolean isOccupied
+ assignVehicle(vehicle: Vehicle)
+ removeVehicle()

Vehicle
- String licensePlate
- VehicleType type

Ticket
- String id
- Vehicle vehicle
- Date entryTime

Payment
+ calculateFee(ticket: Ticket): double

VehicleType: Enum { CAR, BIKE, TRUCK }

πŸ”„Step by step Implementation

import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

// Enum for Vehicle Types
enum VehicleType {
    CAR, BIKE, TRUCK
}

// Vehicle Class
class Vehicle {
    private String licensePlate;
    private VehicleType type;

    public Vehicle(String licensePlate, VehicleType type) {
        this.licensePlate = licensePlate;
        this.type = type;
    }

    public VehicleType getType() {
        return type;
    }

    public String getLicensePlate() {
        return licensePlate;
    }
}

// Parking Spot Class
class ParkingSpot {
    private String id;
    private VehicleType type;
    private boolean isOccupied;
    private Vehicle currentVehicle;
    private final Lock lock = new ReentrantLock();

    public ParkingSpot(String id, VehicleType type) {
        this.id = id;
        this.type = type;
        this.isOccupied = false;
    }

    public boolean assignVehicle(Vehicle vehicle) {
        lock.lock();
        try {
            if (!isOccupied && vehicle.getType() == type) {
                this.currentVehicle = vehicle;
                isOccupied = true;
                return true;
            }
            return false;
        } finally {
            lock.unlock();
        }
    }

    public void removeVehicle() {
        lock.lock();
        try {
            this.currentVehicle = null;
            isOccupied = false;
        } finally {
            lock.unlock();
        }
    }

    public boolean isAvailable() {
        lock.lock();
        try {
            return !isOccupied;
        } finally {
            lock.unlock();
        }
    }
}

// Parking Floor Class
class ParkingFloor {
    private String id;
    private List<ParkingSpot> spots;

    public ParkingFloor(String id, List<ParkingSpot> spots) {
        this.id = id;
        this.spots = spots;
    }

    public ParkingSpot getAvailableSpot(VehicleType type) {
        for (ParkingSpot spot : spots) {
            if (spot.getType() == type && spot.isAvailable()) {
                return spot;
            }
        }
        return null;
    }
}

// Ticket Class
class Ticket {
    private String id;
    private Vehicle vehicle;
    private Date entryTime;

    public Ticket(Vehicle vehicle) {
        this.id = UUID.randomUUID().toString();
        this.vehicle = vehicle;
        this.entryTime = new Date();
    }

    public Date getEntryTime() {
        return entryTime;
    }

    public Vehicle getVehicle() {
        return vehicle;
    }
}

// Payment Strategy Interface
interface PaymentStrategy {
    double calculateFee(long duration);
}

class CarPaymentStrategy implements PaymentStrategy {
    public double calculateFee(long duration) {
        return duration * 5.0;
    }
}

class BikePaymentStrategy implements PaymentStrategy {
    public double calculateFee(long duration) {
        return duration * 2.0;
    }
}

// Parking Lot Class
class ParkingLot {
    private static ParkingLot instance;
    private List<ParkingFloor> floors;
    private Map<String, ParkingSpot> occupiedSpots;

    private ParkingLot() {
        this.floors = new ArrayList<>();
        this.occupiedSpots = new HashMap<>();
    }

    public static ParkingLot getInstance() {
        if (instance == null) {
            instance = new ParkingLot();
        }
        return instance;
    }

    public void addFloor(ParkingFloor floor) {
        floors.add(floor);
    }

    public Ticket parkVehicle(Vehicle vehicle) {
        for (ParkingFloor floor : floors) {
            ParkingSpot spot = floor.getAvailableSpot(vehicle.getType());
            if (spot != null && spot.assignVehicle(vehicle)) {
                occupiedSpots.put(vehicle.getLicensePlate(), spot);
                return new Ticket(vehicle);
            }
        }
        throw new IllegalStateException("No available spot!");
    }

    public double leaveVehicle(Ticket ticket) {
        ParkingSpot spot = occupiedSpots.get(ticket.getVehicle().getLicensePlate());
        if (spot != null) {
            long duration = (new Date().getTime() - ticket.getEntryTime().getTime()) / 3600000;
            PaymentStrategy strategy = ticket.getVehicle().getType() == VehicleType.CAR
                ? new CarPaymentStrategy()
                : new BikePaymentStrategy();
            double fee = strategy.calculateFee(duration);
            spot.removeVehicle();
            occupiedSpots.remove(ticket.getVehicle().getLicensePlate());
            return fee;
        }
        throw new IllegalStateException("Invalid Ticket!");
    }
}

// Demo Class
public class ParkingLotDemo {
    public static void main(String[] args) throws InterruptedException {
        ParkingLot lot = ParkingLot.getInstance();

        // Setup parking lot
        ParkingFloor floor1 = new ParkingFloor("F1", Arrays.asList(
            new ParkingSpot("S1", VehicleType.CAR),
            new ParkingSpot("S2", VehicleType.BIKE)
        ));
        lot.addFloor(floor1);

        // Park a vehicle
        Vehicle car = new Vehicle("CAR123", VehicleType.CAR);
        Ticket ticket = lot.parkVehicle(car);

        // Simulate parking duration
        Thread.sleep(2000);

        // Leave the parking lot
        double fee = lot.leaveVehicle(ticket);
        System.out.println("Parking Fee: $" + fee);
    }
}
0
Subscribe to my newsletter

Read articles from Shohanur Rahman directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Shohanur Rahman
Shohanur Rahman

πŸ‘‹ Hey there! I’m Shohanur Rahman! I’m a backend developer with over 5.5 years of experience in building scalable and efficient web applications. My work focuses on Java, Spring Boot, and microservices architecture, where I love designing robust API solutions and creating secure middleware for complex integrations. πŸ’Ό What I Do Backend Development: Expert in Spring Boot, Spring Cloud, and Spring WebFlux, I create high-performance microservices that drive seamless user experiences. Cloud & DevOps: AWS enthusiast, skilled in using EC2, S3, RDS, and Docker to design scalable and reliable cloud infrastructures. Digital Security: Passionate about securing applications with OAuth2, Keycloak, and digital signatures for data integrity and privacy. πŸš€ Current Projects I’m currently working on API integrations with Spring Cloud Gateway and designing an e-invoicing middleware. My projects often involve asynchronous processing, digital signature implementations, and ensuring high standards of security. πŸ“ Why I Write I enjoy sharing what I’ve learned through blog posts, covering everything from backend design to API security and cloud best practices. Check out my posts if you’re into backend dev, cloud tech, or digital security!